diff --git a/.env.example b/.env.example index a816760..9df1ae4 100644 --- a/.env.example +++ b/.env.example @@ -1,22 +1,2 @@ # Discord bot token -TOKEN= - -# MongoDB -MONGODB_URI= - -# Groq -GROQ_API_KEY= - -# Port, if hosting on Render or similar platforms -PORT=5500 - -# Firebase -FIREBASE_API_KEY= -FIREBASE_AUTH_DOMAIN= -FIREBASE_PROJECT_ID= -FIREBASE_STORAGE_BUCKET= -FIREBASE_MESSAGING_SENDER_ID= -FIREBASE_APP_ID= -FIREBASE_MEASUREMENT_ID= -FIREBASE_CLIENT_EMAIL= -FIREBASE_PRIVATE_KEY= +BOT_TOKEN= diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..dd2d122 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,40 @@ +## What does this PR do? + +Explain here what you changed and why. Doesn't need to be long, just enough +for a reviewer to understand the change without reading every line of +diff. If it was a bug fix, briefly describe what was broken. Delete this paragraph and replace it with your description. + +## Closes + +List any issues that are linked to this pull request (e.g., `Closes #123`). + +- Closes # + +## Type of change(s) + +- [ ] Bug fix +- [ ] New feature +- [ ] Documentation update +- [ ] Refactor (no functional change) +- [ ] Performance improvement +- [ ] Other + +## Checklist + +- [ ] I've tested this change and it works as expected +- [ ] `bun run build` or `npm run build` completes successfully +- [ ] `bun run lint` or `npm run lint` completes without warnings or errors +- [ ] `bun run typecheck` or `npm run typecheck` completes without warnings or errors +- [ ] My code is formatted with prettier (`bun run format` or `npm run format`) +- [ ] My commit messages follow [Conventional Commits](https://www.conventionalcommits.org/) (e.g. `feat: ...`, `fix: ...`, `chore: ...`) +- [ ] I've updated relevant documentation (README, comments, etc.) if needed +- [ ] I've removed any temporary debugging code (e.g. `console.log`) + +## Screenshots / recordings (if applicable) + +If this changes anything visual, a before/after screenshot or a short clip makes review a lot faster. Delete this section if it doesn't apply. + +## Anything else the reviewer should know? + +Extra context, known limitations, or specific things you'd like a +second opinion on. Delete this section if there's nothing to add. diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml new file mode 100644 index 0000000..a8a2e67 --- /dev/null +++ b/.github/workflows/linter.yml @@ -0,0 +1,43 @@ +name: Lint + +on: + pull_request: + push: + branches: + - main + +permissions: + contents: read + statuses: write + +jobs: + lint: + name: Super-Linter + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Run Super-Linter + uses: super-linter/super-linter@v8 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DEFAULT_BRANCH: main + VALIDATE_ALL_CODEBASE: false + VALIDATE_JAVASCRIPT_ES: true + VALIDATE_TYPESCRIPT_STANDARD: true + VALIDATE_BASH: true + VALIDATE_JSON: true + VALIDATE_YAML: true + VALIDATE_ENV: true + VALIDATE_GITHUB_ACTIONS: true + VALIDATE_GIT_MERGE_CONFLICT_MARKERS: true + VALIDATE_JAVASCRIPT_PRETTIER: true + VALIDATE_JSON_PRETTIER: true + VALIDATE_JSONC_PRETTIER: true + VALIDATE_MARKDOWN_PRETTIER: true + VALIDATE_TYPESCRIPT_PRETTIER: true + VALIDATE_YAML_PRETTIER: true diff --git a/.gitignore b/.gitignore index 6f99bf3..13b9f68 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ node_modules/ +dist/ +/db/ .npm/ .bun/ .env -*.key diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..90acf9c --- /dev/null +++ b/.prettierrc @@ -0,0 +1,11 @@ +{ + "semi": true, + "singleQuote": false, + "tabWidth": 2, + "useTabs": false, + "trailingComma": "all", + "printWidth": 80, + "bracketSpacing": true, + "arrowParens": "always", + "endOfLine": "lf" +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 7a91fab..6c8a167 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,5 @@ "source.organizeImports": "explicit", "source.sortMembers": "explicit" }, - "cSpell.words": ["cooldown", "cooldowns", "firestore", "pandabot"] + "editor.defaultFormatter": "esbenp.prettier-vscode" } diff --git a/.zed/settings.json b/.zed/settings.json new file mode 100644 index 0000000..dc9bf20 --- /dev/null +++ b/.zed/settings.json @@ -0,0 +1,7 @@ +{ + "format_on_save": "on", + "code_actions_on_format": { + "source.fixAll": true, + "source.organizeImports": true + } +} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index fadb019..6de0487 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -55,7 +55,7 @@ further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team. All +reported by contacting the project team at [open-devhub@outlook.com](mailto:open-devhub@outlook.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f71b89b..a281027 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,7 +32,7 @@ We welcome all kinds of contributions, whether it's fixing bugs, adding new feat - Commit your work with a meaningful message: ```bash - git commit -m "Add leveling rewards system" + git commit -m "feat(tickets): log message conversation on ticket close" ``` - Push your branch to your fork: ```bash @@ -47,13 +47,14 @@ We welcome all kinds of contributions, whether it's fixing bugs, adding new feat ## πŸ“– Code of Conduct -By contributing, you agree to uphold our [Looks like the result wasn't safe to show. Let's switch things up and try something else!]. +By contributing, you agree to uphold our [Code Of Conduct](./CODE_OF_CONDUCT.md). We expect respectful communication and collaboration. ## πŸ’‘ Suggestions & Ideas Not a coder or not feeling like it? You can still help by: +- Starring the repo - Reporting bugs - Suggesting new features - Improving documentation @@ -61,14 +62,10 @@ Not a coder or not feeling like it? You can still help by: ## 🐼 Recognition -All contributors will be recognized in the project and may receive special roles in the community Discord server. +All contributors will be recognized by special roles in the community Discord server. ## πŸ“œ License -By contributing to this project, you agree that: - -- Your contributions will be licensed under the **DevHub Source-Available License (DSAL)** -- DevHub may use, modify, and distribute your contributions as part of Panda Bot -- You do not gain any ownership, commercial, or hosting rights to Panda Bot by contributing +Panda Bot is released under the **GPL-3.0** License. See [LICENSE](./LICENSE) for details. _Thank you for taking time to contribute to Panda Bot ✨_ diff --git a/LICENSE b/LICENSE index 27deb0e..41e5d76 100644 --- a/LICENSE +++ b/LICENSE @@ -631,8 +631,8 @@ to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - - Copyright (C) + PandaBot - General purpose Discord bot powering the DevHub Discord community + Copyright (C) 2026 Open DevHub This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - Copyright (C) + PandaBot Copyright (C) 2026 Open DevHub This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. diff --git a/README.md b/README.md index 4a5130a..4b5f293 100644 --- a/README.md +++ b/README.md @@ -9,36 +9,30 @@ [![Runtime: Bun](https://img.shields.io/badge/runtime-Bun-f9f1e1?logo=bun&logoColor=white)](https://bun.sh) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](./CONTRIBUTING.md) -Panda keeps DevHub engaging, organized, and fun β€” with community management, moderation, gamification, and a little bit of magic. +Panda is a [self hostable] discord bot that keeps DevHub engaging, organized, and fun with community management, gamification, and a little bit of magic. ---- - ## ✨ Features -| Feature | Description | -| --- | --- | -| πŸ‘‹ **Welcome System** | Greets new members with embeds in the server **and** via DM, plus a sticky introduction message with πŸ‘‹ reactions. | -| πŸ” **Captcha Verification** | New members complete a visual captcha (via DM) before gaining full access; suspended members can verify to restore access. | -| 🎫 **Ticketing System** | Clean support-ticket creation and management with transcripts and an admin log channel. | -| ⭐ **Starboard** | Messages that reach enough reactions are promoted to the starboard channel. | -| πŸ’‘ **Suggestions** | Collect, queue, vote on, and mark community suggestions as implemented. | -| πŸ”’ **Counting Game** | Classic counting-channel game with a per-user count leaderboard, plus reset/set-count tools. | -| πŸ§‘β€πŸ’» **Profiles** | Custom profiles with bio, stack, GitHub, portfolio, hobbies & badge roles (Admin, Developer, VIP, Bug Hunter, and more). | -| 😴 **AFK System** | Set an AFK status and get notified when someone pings you. | -| πŸ“œ **Rule Lookup** | Instantly fetch any rule embed with `p!r`. | -| 🧰 **Moderation Tools** | Purge, lock/unlock, hide/unhide, slowmode, and a user-report context menu. | -| ⚑ **Macros** | Quick community macros triggered with the `++` prefix. | -| πŸ› οΈ **Utility Commands** | Slash + prefix commands: ping, snowflake decoding, DM sending, custom embeds/messages, and more. | +| Feature | Description | +| -------------------- | ------------------------------------------------------------------------------------------------------------------ | +| **Welcome System** | Greets new members with embeds in the server **and** via DM, plus a sticky introduction message with πŸ‘‹ reactions. | +| **Ticketing System** | Clean support-ticket creation and management with transcripts and an admin log channel. | +| **Starboard** | Messages that reach enough reactions are promoted to the starboard channel. | +| **Suggestions** | Collect, queue, vote on, and mark community suggestions as implemented. | +| **Counting Game** | Classic counting-channel game with a per-user count leaderboard, plus reset/set-count tools. | +| **AFK System** | Set an AFK status and get notified when someone pings you. | +| **Rule Lookup** | Instantly fetch any rule embed with `?r`. | +| **Moderation Tools** | Purge, lock/unlock, hide/unhide, slowmode, and a user-report context menu. | +| **Macros** | Quick community macros triggered with the `++` prefix. | ## πŸ› οΈ Tech Stack +- **[Sapphirejs](https://sapphirejs.dev)**: Discord bot framework - **[discord.js](https://discord.js.org)** v14: Discord API - **[Bun](https://bun.sh)**: runtime & package manager -- **[MongoDB](https://www.mongodb.com)** (Mongoose): persistent storage -- **[Firebase](https://firebase.google.com)**: cloud services -- **[captcha-canvas](https://www.npmjs.com/package/captcha-canvas)**: verification captchas +- **[LMDB](https://www.mongodb.com)**: persistent local storage ## πŸš€ Getting Started @@ -46,8 +40,6 @@ Panda keeps DevHub engaging, organized, and fun β€” with community management, m - [Bun](https://bun.sh) >= 1.0 - A [Discord application](https://discord.com/developers/applications) with a bot token -- MongoDB instance (local or [Atlas](https://www.mongodb.com/atlas)) -- (Optional) Firebase project credentials ### Setup @@ -72,7 +64,7 @@ Panda keeps DevHub engaging, organized, and fun β€” with community management, m cp .env.example .env ``` - Then set your Discord token and MongoDB URI in `.env`. + Then set your Discord token in `.env`. 4. **Run the bot** @@ -81,13 +73,12 @@ Panda keeps DevHub engaging, organized, and fun β€” with community management, m bun dev # development with watch mode ``` -> [!TIP] -> Slash commands are registered automatically on startup. Set `REGISTER_COMMANDS=false` in `.env` to skip registration. - ## 🀝 Contributing -We welcome contributions! Open an issue or submit a pull request β€” see [CONTRIBUTING.md](./CONTRIBUTING.md) for detailed guide. +We welcome contributions! Open an issue or submit a pull request. + +Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for detailed guide. ## πŸ“œ License -Panda Bot is released under the **GPL-3.0** License. See [LICENSE](./LICENSE) for details. \ No newline at end of file +Panda Bot is released under the **GPL-3.0** License. See [LICENSE](./LICENSE) for details. diff --git a/bun.lock b/bun.lock index a5a680f..53792bf 100644 --- a/bun.lock +++ b/bun.lock @@ -1,468 +1,462 @@ { - "lockfileVersion": 1, - "configVersion": 0, + "lockfileVersion": 2, + "configVersion": 1, "workspaces": { "": { "name": "pandabot", "dependencies": { + "@sapphire/framework": "^5.5.1", + "@sapphire/plugin-editable-commands": "^4.0.4", "discord.js": "^14.7.1", "dotenv": "^16.0.3", - "firebase-admin": "^13.8.0", + "lmdb": "^3.5.6", "mongoose": "^6.9.0", - "ms": "^2.1.3", - "pretty-ms": "^8.0.0", }, "devDependencies": { + "eslint": "^10.9.1", "prettier": "^3.8.1", + "tsup": "^8.5.1", + "typescript": "6.x", + "typescript-eslint": "^8.69.0", }, }, }, "packages": { - "@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="], + "@aws-sdk/core": ["@aws-sdk/core@3.977.9", "", { "dependencies": { "@aws-sdk/types": "^3.974.5", "@aws-sdk/xml-builder": "^3.972.40", "@aws/lambda-invoke-store": "^0.3.0", "@smithy/core": "^3.33.3", "@smithy/signature-v4": "^5.6.12", "@smithy/types": "^4.17.2", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-reqPFEQrZxDZpeGj4PFMepBeR5LGYHRqq/L0motTzgFkCRBA4rFdaVXDSLYyGHhxVz7sT2PDnPN9CluGSfgyJA=="], - "@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA=="], + "@aws-sdk/credential-provider-cognito-identity": ["@aws-sdk/credential-provider-cognito-identity@3.972.69", "", { "dependencies": { "@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-vpsh9VWmQVC/nsdzf72F2yUMBOFT1aq+hoLseYV03zjVXVHkjqSNJskFRKPFxc3MRFrHNbSSmOwsbYE15u9ecw=="], - "@aws-crypto/supports-web-crypto": ["@aws-crypto/supports-web-crypto@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg=="], + "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.70", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-H404B7dJl2mCrBqahDEYsanB0xhdDp6tXnXcTUnXmmpy2Q3J0Ho0bUajZ2jr/RdwzCyS59Gi8xXIFwPLGBl6Uw=="], - "@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="], + "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.72", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/fetch-http-handler": "^5.7.2", "@smithy/node-http-handler": "^4.11.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-X98zYOrVOeuosCX+6ktf29FC2N2GHPLia7qv6mzPzTc+RPAuHWCDS++Z6JK7eGYqb/v6uaW7bAXaOvDBfol+0w=="], - "@aws-sdk/client-cognito-identity": ["@aws-sdk/client-cognito-identity@3.948.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/credential-provider-node": "3.948.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-xuf0zODa1zxiCDEcAW0nOsbkXHK9QnK6KFsCatSdcIsg1zIaGCui0Cg3HCm/gjoEgv+4KkEpYmzdcT5piedzxA=="], + "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.973.15", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/credential-provider-env": "^3.972.70", "@aws-sdk/credential-provider-http": "^3.972.72", "@aws-sdk/credential-provider-login": "^3.972.77", "@aws-sdk/credential-provider-process": "^3.972.70", "@aws-sdk/credential-provider-sso": "^3.973.14", "@aws-sdk/credential-provider-web-identity": "^3.972.76", "@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/credential-provider-imds": "^4.4.16", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-Rykg6s5ceBuynMOGWgoowO4N+27JfnqXAnVaSunZl0hOO1XodSrxGNz6sCEbnmS0lAfQZDKyb3fbr46gSuv6Sg=="], - "@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.948.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-iWjchXy8bIAVBUsKnbfKYXRwhLgRg3EqCQ5FTr3JbR+QR75rZm4ZOYXlvHGztVTmtAZ+PQVA1Y4zO7v7N87C0A=="], + "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.77", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-Jb59xfEISoN5mmbnA+HYqdtrSX3CgCtJoof+V5D8/TgUI56W63GEEd5Y58WijU3Ou6+WEgaLD1feVzaRXV5IDQ=="], - "@aws-sdk/core": ["@aws-sdk/core@3.947.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw=="], + "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.81", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.70", "@aws-sdk/credential-provider-http": "^3.972.72", "@aws-sdk/credential-provider-ini": "^3.973.15", "@aws-sdk/credential-provider-process": "^3.972.70", "@aws-sdk/credential-provider-sso": "^3.973.14", "@aws-sdk/credential-provider-web-identity": "^3.972.76", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/credential-provider-imds": "^4.4.16", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-Rml+WitoFvXmv6JZ18U/xGdGDGGvB/mOin0ya0lTnTrdC0Z1lrVxTYh7iNklZBcvcRMrs4DoEf6xy1KWyrLQQw=="], - "@aws-sdk/credential-provider-cognito-identity": ["@aws-sdk/credential-provider-cognito-identity@3.948.0", "", { "dependencies": { "@aws-sdk/client-cognito-identity": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-qWzS4aJj09sHJ4ZPLP3UCgV2HJsqFRNtseoDlvmns8uKq4ShaqMoqJrN6A9QTZT7lEBjPFsfVV4Z7Eh6a0g3+g=="], + "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.70", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-2ry03fGRJr4sV3jI+ocjj5JqALnFD6ymM5KiNCDZMvq8bX2GSbE0vji4aM43TVCl2nXqqLRZaUxdq/KeWRAY4Q=="], - "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-VR2V6dRELmzwAsCpK4GqxUi6UW5WNhAXS9F9AzWi5jvijwJo3nH92YNJUP4quMpgFZxJHEWyXLWgPjh9u0zYOA=="], + "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.973.14", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/token-providers": "3.1116.0", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-jkhg/8ocAAoc0RFyLMhCw+/zZh7gystQgd4F4hznNa8P4Cc501PQmxd+jGLiMHodPJ+7Zv/3znM62gZojyasmA=="], - "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-inF09lh9SlHj63Vmr5d+LmwPXZc2IbK8lAruhOr3KLsZAIHEgHgGPXWDC2ukTEMzg0pkexQ6FOhXXad6klK4RA=="], + "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.76", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-d3AGyVu759PGr35mEB2s22xxlNEA5rpdxtSPJthfPFJvoQ8dt357iVPECqWfUxXp1toJAvKmbtcIYVGigaGsCA=="], - "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.948.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/credential-provider-env": "3.947.0", "@aws-sdk/credential-provider-http": "3.947.0", "@aws-sdk/credential-provider-login": "3.948.0", "@aws-sdk/credential-provider-process": "3.947.0", "@aws-sdk/credential-provider-sso": "3.948.0", "@aws-sdk/credential-provider-web-identity": "3.948.0", "@aws-sdk/nested-clients": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Cl//Qh88e8HBL7yYkJNpF5eq76IO6rq8GsatKcfVBm7RFVxCqYEPSSBtkHdbtNwQdRQqAMXc6E/lEB/CZUDxnA=="], + "@aws-sdk/credential-providers": ["@aws-sdk/credential-providers@3.1118.0", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/credential-provider-cognito-identity": "^3.972.69", "@aws-sdk/credential-provider-env": "^3.972.70", "@aws-sdk/credential-provider-http": "^3.972.72", "@aws-sdk/credential-provider-ini": "^3.973.15", "@aws-sdk/credential-provider-login": "^3.972.77", "@aws-sdk/credential-provider-node": "^3.972.81", "@aws-sdk/credential-provider-process": "^3.972.70", "@aws-sdk/credential-provider-sso": "^3.973.14", "@aws-sdk/credential-provider-web-identity": "^3.972.76", "@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/credential-provider-imds": "^4.4.16", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-UDo7cEXbIEDqcHOiVBCrk4tuJhWwtREKH5hMtW+BYetA++SgfNutmTm0fmcuT6TpKFBLxA2Jm5PRzXXs2pImGw=="], - "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.948.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-gcKO2b6eeTuZGp3Vvgr/9OxajMrD3W+FZ2FCyJox363ZgMoYJsyNid1vuZrEuAGkx0jvveLXfwiVS0UXyPkgtw=="], + "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.44", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/signature-v4-multi-region": "^3.996.46", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/fetch-http-handler": "^5.7.2", "@smithy/node-http-handler": "^4.11.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-NhEgryjlBF9w38ZXqGymQV28IhkYa1mKhlbYnqIis57AYwWGVYfUPgg/qC2rLRqOUfblxx++irvju10kVTa8Vw=="], - "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.948.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.947.0", "@aws-sdk/credential-provider-http": "3.947.0", "@aws-sdk/credential-provider-ini": "3.948.0", "@aws-sdk/credential-provider-process": "3.947.0", "@aws-sdk/credential-provider-sso": "3.948.0", "@aws-sdk/credential-provider-web-identity": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-ep5vRLnrRdcsP17Ef31sNN4g8Nqk/4JBydcUJuFRbGuyQtrZZrVT81UeH2xhz6d0BK6ejafDB9+ZpBjXuWT5/Q=="], + "@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.46", "", { "dependencies": { "@aws-sdk/types": "^3.974.5", "@smithy/signature-v4": "^5.6.12", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-L+2xZTye/2T96f3lwCws0Zw6GG2JHZW9e8FpVgGBeeExSKyeoZ6CWRpBml/7DNiK/O26jrgPM9F+Ay8VkgzUWQ=="], - "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-WpanFbHe08SP1hAJNeDdBDVz9SGgMu/gc0XJ9u3uNpW99nKZjDpvPRAdW7WLA4K6essMjxWkguIGNOpij6Do2Q=="], + "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1116.0", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-ygIivKqh8aHzNkucOCXHyIBgBpLPfrSI0mCqXF+vLBsPTUKqj0VSqAY0GFPe7lQl4HntjOcQ+KSyS7oUV2C54Q=="], - "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.948.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.948.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/token-providers": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-gqLhX1L+zb/ZDnnYbILQqJ46j735StfWV5PbDjxRzBKS7GzsiYoaf6MyHseEopmWrez5zl5l6aWzig7UpzSeQQ=="], + "@aws-sdk/types": ["@aws-sdk/types@3.974.5", "", { "dependencies": { "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-LkwLL2BLbC6wNNm4JaH9mbEqBMdOZCct6VAYqhdN4U1xrWM+fUJQEfbHwQgDypapOWTRtlk25akb5afM0P8CIQ=="], - "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.948.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-MvYQlXVoJyfF3/SmnNzOVEtANRAiJIObEUYYyjTqKZTmcRIVVky0tPuG26XnB8LmTYgtESwJIZJj/Eyyc9WURQ=="], + "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.40", "", { "dependencies": { "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-wlFmCIGUlwF4zx/kncw+bmxTQh1HeSJq4mYV/V5cZUSJadDP3kXvGW8Rn21cimj/7y9ju+47oYWXi97vF7czaA=="], - "@aws-sdk/credential-providers": ["@aws-sdk/credential-providers@3.948.0", "", { "dependencies": { "@aws-sdk/client-cognito-identity": "3.948.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/credential-provider-cognito-identity": "3.948.0", "@aws-sdk/credential-provider-env": "3.947.0", "@aws-sdk/credential-provider-http": "3.947.0", "@aws-sdk/credential-provider-ini": "3.948.0", "@aws-sdk/credential-provider-login": "3.948.0", "@aws-sdk/credential-provider-node": "3.948.0", "@aws-sdk/credential-provider-process": "3.947.0", "@aws-sdk/credential-provider-sso": "3.948.0", "@aws-sdk/credential-provider-web-identity": "3.948.0", "@aws-sdk/nested-clients": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-puFIZzSxByrTS7Ffn+zIjxlyfI0ELjjwvISVUTAZPmH5Jl95S39+A+8MOOALtFQcxLO7UEIiJFJIIkNENK+60w=="], + "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.3.0", "", {}, "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ=="], - "@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="], + "@discordjs/builders": ["@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.40", "fast-deep-equal": "^3.1.3", "ts-mixer": "^6.0.4", "tslib": "^2.6.3" } }, "sha512-gSKkhXLqs96TCzk66VZuHHl8z2bQMJFGwrXC0f33ngK+FLNau4hU1PYny3DNJfNdSH+gVMzE85/d5FQ2BpcNwQ=="], - "@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw=="], + "@discordjs/collection": ["@discordjs/collection@1.5.3", "", {}, "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ=="], - "@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.948.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Qa8Zj+EAqA0VlAVvxpRnpBpIWJI9KUwaioY1vkeNVwXPlNaz9y9zCKVM9iU9OZ5HXpoUg6TnhATAHXHAE8+QsQ=="], + "@discordjs/formatters": ["@discordjs/formatters@0.6.2", "", { "dependencies": { "discord-api-types": "^0.38.33" } }, "sha512-y4UPwWhH6vChKRkGdMB4odasUbHOUwy7KL+OVwF86PvT6QVOwElx+TiI1/6kcmcEe+g5YRXJFiXSXUdabqZOvQ=="], - "@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.7", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-7rpKV8YNgCP2R4F9RjWZFcD2R+SO/0R4VHIbY9iZJdH2MzzJ8ZG7h8dZ2m8QkQd1fjx4wrFJGGPJUTYXPV3baA=="], + "@discordjs/rest": ["@discordjs/rest@2.6.3", "", { "dependencies": { "@discordjs/collection": "^2.1.1", "@discordjs/util": "^1.2.0", "@sapphire/async-queue": "^1.5.3", "@sapphire/snowflake": "^3.5.5", "@vladfrangu/async_event_emitter": "^2.4.6", "discord-api-types": "^0.38.50", "magic-bytes.js": "^1.13.0", "tslib": "^2.6.3", "undici": "^6.27.0" } }, "sha512-wvOylxNYJkwKjctS/Mn5GP1w9r3/rzyH+ThD1JlAca6zEdlHs8QWBBUQJpU5Q+W6DoIj/Ljh1IPlZs7hTU+UAg=="], - "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.948.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zcbJfBsB6h254o3NuoEkf0+UY1GpE9ioiQdENWv7odo69s8iaGBEQ4BDpsIMqcuiiUXw1uKIVNxCB1gUGYz8lw=="], + "@discordjs/util": ["@discordjs/util@1.2.0", "", { "dependencies": { "discord-api-types": "^0.38.33" } }, "sha512-3LKP7F2+atl9vJFhaBjn4nOaSWahZ/yWjOvA4e5pnXkt2qyXRCHLxoBQy81GFtLGCq7K9lPm9R517M1U+/90Qg=="], - "@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="], + "@discordjs/ws": ["@discordjs/ws@1.2.3", "", { "dependencies": { "@discordjs/collection": "^2.1.0", "@discordjs/rest": "^2.5.1", "@discordjs/util": "^1.1.0", "@sapphire/async-queue": "^1.5.2", "@types/ws": "^8.5.10", "@vladfrangu/async_event_emitter": "^2.2.4", "discord-api-types": "^0.38.1", "tslib": "^2.6.2", "ws": "^8.17.0" } }, "sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw=="], - "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.948.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-V487/kM4Teq5dcr1t5K6eoUKuqlGr9FRWL3MIMukMERJXHZvio6kox60FZ/YtciRHRI75u14YUqm2Dzddcu3+A=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="], - "@aws-sdk/types": ["@aws-sdk/types@3.936.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg=="], + "@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="], - "@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-endpoints": "^3.2.5", "tslib": "^2.6.2" } }, "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w=="], + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.7", "", { "os": "android", "cpu": "arm64" }, "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ=="], - "@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.893.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-T89pFfgat6c8nMmpI8eKjBcDcgJq36+m9oiXbcUzeU55MP9ZuGgBomGjGnHaEyF36jenW9gmg3NfZDm0AO2XPg=="], + "@esbuild/android-x64": ["@esbuild/android-x64@0.27.7", "", { "os": "android", "cpu": "x64" }, "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg=="], - "@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw=="], + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw=="], - "@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.947.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-+vhHoDrdbb+zerV4noQk1DHaUMNzWFWPpPYjVTwW2186k5BEJIecAMChYkghRrBVJ3KPWP1+JnZwOd72F3d4rQ=="], + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ=="], - "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.930.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" } }, "sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA=="], + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.7", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w=="], - "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.2", "", {}, "sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg=="], + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.7", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ=="], - "@discordjs/builders": ["@discordjs/builders@1.13.1", "", { "dependencies": { "@discordjs/formatters": "^0.6.2", "@discordjs/util": "^1.2.0", "@sapphire/shapeshift": "^4.0.0", "discord-api-types": "^0.38.33", "fast-deep-equal": "^3.1.3", "ts-mixer": "^6.0.4", "tslib": "^2.6.3" } }, "sha512-cOU0UDHc3lp/5nKByDxkmRiNZBpdp0kx55aarbiAfakfKJHlxv/yFW1zmIqCAmwH5CRlrH9iMFKJMpvW4DPB+w=="], + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.7", "", { "os": "linux", "cpu": "arm" }, "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA=="], - "@discordjs/collection": ["@discordjs/collection@1.5.3", "", {}, "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ=="], + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A=="], - "@discordjs/formatters": ["@discordjs/formatters@0.6.2", "", { "dependencies": { "discord-api-types": "^0.38.33" } }, "sha512-y4UPwWhH6vChKRkGdMB4odasUbHOUwy7KL+OVwF86PvT6QVOwElx+TiI1/6kcmcEe+g5YRXJFiXSXUdabqZOvQ=="], + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.7", "", { "os": "linux", "cpu": "ia32" }, "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg=="], - "@discordjs/rest": ["@discordjs/rest@2.6.0", "", { "dependencies": { "@discordjs/collection": "^2.1.1", "@discordjs/util": "^1.1.1", "@sapphire/async-queue": "^1.5.3", "@sapphire/snowflake": "^3.5.3", "@vladfrangu/async_event_emitter": "^2.4.6", "discord-api-types": "^0.38.16", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", "undici": "6.21.3" } }, "sha512-RDYrhmpB7mTvmCKcpj+pc5k7POKszS4E2O9TYc+U+Y4iaCP+r910QdO43qmpOja8LRr1RJ0b3U+CqVsnPqzf4w=="], + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q=="], - "@discordjs/util": ["@discordjs/util@1.2.0", "", { "dependencies": { "discord-api-types": "^0.38.33" } }, "sha512-3LKP7F2+atl9vJFhaBjn4nOaSWahZ/yWjOvA4e5pnXkt2qyXRCHLxoBQy81GFtLGCq7K9lPm9R517M1U+/90Qg=="], + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw=="], - "@discordjs/ws": ["@discordjs/ws@1.2.3", "", { "dependencies": { "@discordjs/collection": "^2.1.0", "@discordjs/rest": "^2.5.1", "@discordjs/util": "^1.1.0", "@sapphire/async-queue": "^1.5.2", "@types/ws": "^8.5.10", "@vladfrangu/async_event_emitter": "^2.2.4", "discord-api-types": "^0.38.1", "tslib": "^2.6.2", "ws": "^8.17.0" } }, "sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw=="], + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.7", "", { "os": "linux", "cpu": "ppc64" }, "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ=="], - "@fastify/busboy": ["@fastify/busboy@3.2.0", "", {}, "sha512-m9FVDXU3GT2ITSe0UaMA5rU3QkfC/UXtCU8y0gSN/GugTqtVldOBWIB5V6V3sbmenVZUIpU6f+mPEO2+m5iTaA=="], + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ=="], - "@firebase/app-check-interop-types": ["@firebase/app-check-interop-types@0.3.3", "", {}, "sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A=="], + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.7", "", { "os": "linux", "cpu": "s390x" }, "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw=="], - "@firebase/app-types": ["@firebase/app-types@0.9.3", "", {}, "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw=="], + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.7", "", { "os": "linux", "cpu": "x64" }, "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA=="], - "@firebase/auth-interop-types": ["@firebase/auth-interop-types@0.2.4", "", {}, "sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA=="], + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w=="], - "@firebase/component": ["@firebase/component@0.7.0", "", { "dependencies": { "@firebase/util": "1.13.0", "tslib": "^2.1.0" } }, "sha512-wR9En2A+WESUHexjmRHkqtaVH94WLNKt6rmeqZhSLBybg4Wyf0Umk04SZsS6sBq4102ZsDBFwoqMqJYj2IoDSg=="], + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.7", "", { "os": "none", "cpu": "x64" }, "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw=="], - "@firebase/database": ["@firebase/database@1.1.0", "", { "dependencies": { "@firebase/app-check-interop-types": "0.3.3", "@firebase/auth-interop-types": "0.2.4", "@firebase/component": "0.7.0", "@firebase/logger": "0.5.0", "@firebase/util": "1.13.0", "faye-websocket": "0.11.4", "tslib": "^2.1.0" } }, "sha512-gM6MJFae3pTyNLoc9VcJNuaUDej0ctdjn3cVtILo3D5lpp0dmUHHLFN/pUKe7ImyeB1KAvRlEYxvIHNF04Filg=="], + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.7", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A=="], - "@firebase/database-compat": ["@firebase/database-compat@2.1.0", "", { "dependencies": { "@firebase/component": "0.7.0", "@firebase/database": "1.1.0", "@firebase/database-types": "1.0.16", "@firebase/logger": "0.5.0", "@firebase/util": "1.13.0", "tslib": "^2.1.0" } }, "sha512-8nYc43RqxScsePVd1qe1xxvWNf0OBnbwHxmXJ7MHSuuTVYFO3eLyLW3PiCKJ9fHnmIz4p4LbieXwz+qtr9PZDg=="], + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.7", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg=="], - "@firebase/database-types": ["@firebase/database-types@1.0.16", "", { "dependencies": { "@firebase/app-types": "0.9.3", "@firebase/util": "1.13.0" } }, "sha512-xkQLQfU5De7+SPhEGAXFBnDryUWhhlFXelEg2YeZOQMCdoe7dL64DDAd77SQsR+6uoXIZY5MB4y/inCs4GTfcw=="], + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw=="], - "@firebase/logger": ["@firebase/logger@0.5.0", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-cGskaAvkrnh42b3BA3doDWeBmuHFO/Mx5A83rbRDYakPjO9bJtRL3dX7javzc2Rr/JHZf4HlterTW2lUkfeN4g=="], + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.7", "", { "os": "sunos", "cpu": "x64" }, "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA=="], - "@firebase/util": ["@firebase/util@1.13.0", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-0AZUyYUfpMNcztR5l09izHwXkZpghLgCUaAGjtMwXnCg3bj4ml5VgiwqOMOxJ+Nw4qN/zJAaOQBcJ7KGkWStqQ=="], + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA=="], - "@google-cloud/firestore": ["@google-cloud/firestore@7.11.6", "", { "dependencies": { "@opentelemetry/api": "^1.3.0", "fast-deep-equal": "^3.1.1", "functional-red-black-tree": "^1.0.1", "google-gax": "^4.3.3", "protobufjs": "^7.2.6" } }, "sha512-EW/O8ktzwLfyWBOsNuhRoMi8lrC3clHM5LVFhGvO1HCsLozCOOXRAlHrYBoE6HL42Sc8yYMuCb2XqcnJ4OOEpw=="], + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.7", "", { "os": "win32", "cpu": "ia32" }, "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw=="], - "@google-cloud/paginator": ["@google-cloud/paginator@5.0.2", "", { "dependencies": { "arrify": "^2.0.0", "extend": "^3.0.2" } }, "sha512-DJS3s0OVH4zFDB1PzjxAsHqJT6sKVbRwwML0ZBP9PbU7Yebtu/7SWMRzvO2J3nUi9pRNITCfu4LJeooM2w4pjg=="], + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="], - "@google-cloud/projectify": ["@google-cloud/projectify@4.0.0", "", {}, "sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA=="], + "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.10.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg=="], - "@google-cloud/promisify": ["@google-cloud/promisify@4.0.0", "", {}, "sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g=="], + "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], - "@google-cloud/storage": ["@google-cloud/storage@7.19.0", "", { "dependencies": { "@google-cloud/paginator": "^5.0.0", "@google-cloud/projectify": "^4.0.0", "@google-cloud/promisify": "<4.1.0", "abort-controller": "^3.0.0", "async-retry": "^1.3.3", "duplexify": "^4.1.3", "fast-xml-parser": "^5.3.4", "gaxios": "^6.0.2", "google-auth-library": "^9.6.3", "html-entities": "^2.5.2", "mime": "^3.0.0", "p-limit": "^3.0.1", "retry-request": "^7.0.0", "teeny-request": "^9.0.0", "uuid": "^8.0.0" } }, "sha512-n2FjE7NAOYyshogdc7KQOl/VZb4sneqPjWouSyia9CMDdMhRX5+RIbqalNmC7LOLzuLAN89VlF2HvG8na9G+zQ=="], + "@eslint/config-array": ["@eslint/config-array@0.23.5", "", { "dependencies": { "@eslint/object-schema": "^3.0.5", "debug": "^4.3.1", "minimatch": "^10.2.4" } }, "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA=="], - "@grpc/grpc-js": ["@grpc/grpc-js@1.14.3", "", { "dependencies": { "@grpc/proto-loader": "^0.8.0", "@js-sdsl/ordered-map": "^4.4.2" } }, "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA=="], + "@eslint/config-helpers": ["@eslint/config-helpers@0.7.0", "", { "dependencies": { "@eslint/core": "^1.2.1" } }, "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw=="], - "@grpc/proto-loader": ["@grpc/proto-loader@0.7.15", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.2.5", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ=="], + "@eslint/core": ["@eslint/core@1.2.1", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ=="], - "@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="], + "@eslint/object-schema": ["@eslint/object-schema@3.0.5", "", {}, "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw=="], - "@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.4.0", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-ZHzx7Z3rdlWL1mECydvpryWN/ETXJiCxdgQKTAH+djzIPe77HdnSizKBDi1TVDXZjXyOj2IqEG/vPw71ULF06w=="], + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.7.2", "", { "dependencies": { "@eslint/core": "^1.2.1", "levn": "^0.4.1" } }, "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A=="], - "@nodable/entities": ["@nodable/entities@2.1.0", "", {}, "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA=="], + "@harperfast/extended-iterable": ["@harperfast/extended-iterable@1.0.3", "", {}, "sha512-sSAYhQca3rDWtQUHSAPeO7axFIUJOI6hn1gjRC5APVE1a90tuyT8f5WIgRsFhhWA7htNkju2veB9eWL6YHi/Lw=="], - "@opentelemetry/api": ["@opentelemetry/api@1.9.1", "", {}, "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q=="], + "@humanfs/core": ["@humanfs/core@0.19.2", "", { "dependencies": { "@humanfs/types": "^0.15.0" } }, "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA=="], - "@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="], + "@humanfs/node": ["@humanfs/node@0.16.8", "", { "dependencies": { "@humanfs/core": "^0.19.2", "@humanfs/types": "^0.15.0", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ=="], - "@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="], + "@humanfs/types": ["@humanfs/types@0.15.0", "", {}, "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q=="], - "@protobufjs/codegen": ["@protobufjs/codegen@2.0.4", "", {}, "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="], + "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], - "@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="], + "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], - "@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ=="], + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], - "@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="], + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], - "@protobufjs/inquire": ["@protobufjs/inquire@1.1.0", "", {}, "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="], + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], - "@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="], + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - "@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="], + "@lmdb/lmdb-darwin-arm64": ["@lmdb/lmdb-darwin-arm64@3.5.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-mY5FG4TjPAkY4P0w+OhHaUka5mDh2TX2WKYIwuKzJ1zeW3VvRgxdam/lGJTquI+bthTx5CSHDW+BAQCnNAzkEA=="], - "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="], + "@lmdb/lmdb-darwin-x64": ["@lmdb/lmdb-darwin-x64@3.5.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-foa+pwitysO8k+xhs7psBFfTKnVgR69NlZRRTHaFVDqphh7AdGpLeyRzKw/ofatr/sN6TiHRRW6mmop0ZrrppQ=="], - "@sapphire/async-queue": ["@sapphire/async-queue@1.5.5", "", {}, "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg=="], - - "@sapphire/shapeshift": ["@sapphire/shapeshift@4.0.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "lodash": "^4.17.21" } }, "sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg=="], + "@lmdb/lmdb-linux-arm": ["@lmdb/lmdb-linux-arm@3.5.6", "", { "os": "linux", "cpu": "arm" }, "sha512-QR4YRyR5h5Z8eGXrNQjiyo2NNDfqi3tCc9dQG5Is1blCt+qWw1ZoBWhlWAr5d+jshkifMIJjVHzHGKbkKzF8Tw=="], - "@sapphire/snowflake": ["@sapphire/snowflake@3.5.3", "", {}, "sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ=="], + "@lmdb/lmdb-linux-arm64": ["@lmdb/lmdb-linux-arm64@3.5.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-HmiyFFdJa38s1heCMSooSPaBSFTHJ3C+ERPp28xAPlDX1YiALJVOgbry065nXd8Y7KISWjnw05zpG1RX8IfftA=="], - "@smithy/abort-controller": ["@smithy/abort-controller@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-j7HwVkBw68YW8UmFRcjZOmssE77Rvk0GWAIN1oFBhsaovQmZWYCIcGa9/pwRB0ExI8Sk9MWNALTjftjHZea7VA=="], + "@lmdb/lmdb-linux-x64": ["@lmdb/lmdb-linux-x64@3.5.6", "", { "os": "linux", "cpu": "x64" }, "sha512-ADzCuCF2cTNiX9kDScqcz1fjnAkxPpQNneV3KFTdV3wWtVlI2sTGzySoMTgDpinkMMFj1NTJlxA6XR8fwc4hlA=="], - "@smithy/config-resolver": ["@smithy/config-resolver@4.4.3", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-ezHLe1tKLUxDJo2LHtDuEDyWXolw8WGOR92qb4bQdWq/zKenO5BvctZGrVJBK08zjezSk7bmbKFOXIVyChvDLw=="], + "@lmdb/lmdb-win32-arm64": ["@lmdb/lmdb-win32-arm64@3.5.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-J7A9aEQsQiv0TYtBGL7NDIPp2lOS8nnl+zm4sWZm1xlsTTaQ4PgD096Adzdrk27rw3UxCkDXdCUa4ax41oztBQ=="], - "@smithy/core": ["@smithy/core@3.18.7", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.6", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-axG9MvKhMWOhFbvf5y2DuyTxQueO0dkedY9QC3mAfndLosRI/9LJv8WaL0mw7ubNhsO4IuXX9/9dYGPFvHrqlw=="], + "@lmdb/lmdb-win32-x64": ["@lmdb/lmdb-win32-x64@3.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-1g7G0knRX2iV/voDu54yxrGqw5Dk0w2oIYb7dgJq8IkOi+m7wbD8Q3QpPFjh0C01G58S88dqGn03len6UPCXsg=="], - "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.5", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-BZwotjoZWn9+36nimwm/OLIcVe+KYRwzMjfhd4QT7QxPm9WY0HiOV8t/Wlh+HVUif0SBVV7ksq8//hPaBC/okQ=="], + "@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.5.0", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-Hk1SKJCMcCos38+vqDnZzlIo4XRj9yCGzYkjB4LcqpeXRIYfia1UWTz+VrueLxoU+uSRJzgkufxoRZg8gi52YA=="], - "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.6", "", { "dependencies": { "@smithy/protocol-http": "^5.3.5", "@smithy/querystring-builder": "^4.2.5", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" } }, "sha512-3+RG3EA6BBJ/ofZUeTFJA7mHfSYrZtQIrDP9dI8Lf7X6Jbos2jptuLrAAteDiFVrmbEmLSuRG/bUKzfAXk7dhg=="], + "@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ=="], - "@smithy/hash-node": ["@smithy/hash-node@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DpYX914YOfA3UDT9CN1BM787PcHfWRBB43fFGCYrZFUH0Jv+5t8yYl+Pd5PW4+QzoGEDvn5d5QIO4j2HyYZQSA=="], + "@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w=="], - "@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-2L2erASEro1WC5nV+plwIMxrTXpvpfzl4e+Nre6vBVRR2HKeGGcvpJyyL3/PpiSg+cJG2KpTmZmq934Olb6e5A=="], + "@msgpackr-extract/msgpackr-extract-linux-arm": ["@msgpackr-extract/msgpackr-extract-linux-arm@3.0.4", "", { "os": "linux", "cpu": "arm" }, "sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw=="], - "@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ=="], + "@msgpackr-extract/msgpackr-extract-linux-arm64": ["@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw=="], - "@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.5", "", { "dependencies": { "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Y/RabVa5vbl5FuHYV2vUCwvh/dqzrEY/K2yWPSqvhFUwIY0atLqO4TienjBXakoy4zrKAMCZwg+YEqmH7jaN7A=="], + "@msgpackr-extract/msgpackr-extract-linux-x64": ["@msgpackr-extract/msgpackr-extract-linux-x64@3.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ=="], - "@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.3.14", "", { "dependencies": { "@smithy/core": "^3.18.7", "@smithy/middleware-serde": "^4.2.6", "@smithy/node-config-provider": "^4.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-middleware": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-v0q4uTKgBM8dsqGjqsabZQyH85nFaTnFcgpWU1uydKFsdyyMzfvOkNum9G7VK+dOP01vUnoZxIeRiJ6uD0kjIg=="], + "@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4", "", { "os": "win32", "cpu": "x64" }, "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ=="], - "@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.14", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.5", "@smithy/protocol-http": "^5.3.5", "@smithy/service-error-classification": "^4.2.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-Z2DG8Ej7FyWG1UA+7HceINtSLzswUgs2np3sZX0YBBxCt+CXG4QUxv88ZDS3+2/1ldW7LqtSY1UO/6VQ1pND8Q=="], + "@napi-rs/lzma-linux-x64-gnu": ["@napi-rs/lzma-linux-x64-gnu@1.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ=="], - "@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.6", "", { "dependencies": { "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-VkLoE/z7e2g8pirwisLz8XJWedUSY8my/qrp81VmAdyrhi94T+riBfwP+AOEEFR9rFTSonC/5D2eWNmFabHyGQ=="], + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.63.0", "", { "os": "android", "cpu": "arm" }, "sha512-70TeIFezKKy65LgAVyQh+w94/gjWhvPWaLaGGeMEgVrPkQhuj/M5bAYYZzIFUj9Y69oHyTm5Um/R6gcLh4A8JA=="], - "@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-bYrutc+neOyWxtZdbB2USbQttZN0mXaOyYLIsaTbJhFsfpXyGWUxJpEuO1rJ8IIJm2qH4+xJT0mxUSsEDTYwdQ=="], + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.63.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YC86tYIHK6M1IV+wbzO+Bxk8RCBr6ZyWYgWxUCzaZD8mc8rrFoIJDNzDrkHBYRc/wKdrsIXmm6/F7NzrAO+OrA=="], - "@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-UTurh1C4qkVCtqggI36DGbLB2Kv8UlcFdMXDcWMbqVY2uRg0XmT9Pb4Vj6oSQ34eizO1fvR0RnFV4Axw4IrrAg=="], + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.63.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-oI+ECtUcli0y0fi4xpW82GdPIXdTkI8G8DSjG2LRuw09fPAGykaWYH/hXxiKuTxiAjiPSTIIuYUqof5Z2hShWw=="], - "@smithy/node-http-handler": ["@smithy/node-http-handler@4.4.5", "", { "dependencies": { "@smithy/abort-controller": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/querystring-builder": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-CMnzM9R2WqlqXQGtIlsHMEZfXKJVTIrqCNoSd/QpAyp+Dw0a1Vps13l6ma1fH8g7zSPNsA59B/kWgeylFuA/lw=="], + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.63.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-NwV+1s7TiKrMe4owHyKB/dTLD7ZJD0YEBEhIz+hvav1Cu1GReJjF+rsdNwjzENQeIAbE/CoNiaAc5Vz2h5DPAA=="], - "@smithy/property-provider": ["@smithy/property-provider@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-8iLN1XSE1rl4MuxvQ+5OSk/Zb5El7NJZ1td6Tn+8dQQHIjp59Lwl6bd0+nzw6SKm2wSSriH2v/I9LPzUic7EOg=="], + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.63.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-tWtHBTu5gOPK4u4Urtk4qAHW3zZ9rQAmbssO8gp7ELvGTGI3aCiq6NqyTQ0PCIg7KbHJF2UkGDDs77YZGxfjCA=="], - "@smithy/protocol-http": ["@smithy/protocol-http@5.3.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-RlaL+sA0LNMp03bf7XPbFmT5gN+w3besXSWMkA8rcmxLSVfiEXElQi4O2IWwPfxzcHkxqrwBFMbngB8yx/RvaQ=="], + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.63.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-2qPoJiwTvtHQ27NnYvTnsgk8laXWYuVmNESG8WFZBcEPKLfZ3I27qBJarjVRQtwGeYyRfq5ZowHXih9lm2BItw=="], - "@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-y98otMI1saoajeik2kLfGyRp11e5U/iJYH/wLCh3aTV/XutbGT9nziKGkgCaMD1ghK7p6htHMm6b6scl9JRUWg=="], + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.63.0", "", { "os": "linux", "cpu": "arm" }, "sha512-FQwsTRvLNuHoTdICABJQfbPUSEueISGmnpT06tXTMpfprf5NiKLSXKA0A+w45wJnCmZAnzgqBwbt6ARFuyOi5w=="], - "@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-031WCTdPYgiQRYNPXznHXof2YM0GwL6SeaSyTH/P72M1Vz73TvCNH2Nq8Iu2IEPq9QP2yx0/nrw5YmSeAi/AjQ=="], + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.63.0", "", { "os": "linux", "cpu": "arm" }, "sha512-BBVTXziw8mY1a4ZbWME9tZyfzqXCDPqaC7Z3heQ29p5dkvXzwL0NwelO8zLa8c3RBKvl3YTuSnBgsBhYBtwjIw=="], - "@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0" } }, "sha512-8fEvK+WPE3wUAcDvqDQG1Vk3ANLR8Px979te96m84CbKAjBVf25rPYSzb4xU4hlTyho7VhOGnh5i62D/JVF0JQ=="], + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.63.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-w2Iyy9+RqKwx3d9qWMKsJg0FfRBsY0/pXNv0mCQ3ueRvJI6+QAScfD4nrMlzFLs2HNVW6Ew+mtZfDl9b7Ew5/Q=="], - "@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.0", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-5WmZ5+kJgJDjwXXIzr1vDTG+RhF9wzSODQBfkrQ2VVkYALKGvZX1lgVSxEkgicSAFnFhPj5rudJV0zoinqS0bA=="], + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.63.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-YK++KtrFRHYE0P6/RtYEAy9t8F37znP+K03RrIuLPYOL6SVlObRumf/0OE4V/h63xL9DwkWbNssZfmA9hawuDA=="], - "@smithy/signature-v4": ["@smithy/signature-v4@5.3.5", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-xSUfMu1FT7ccfSXkoLl/QRQBi2rOvi3tiBZU2Tdy3I6cgvZ6SEi9QNey+lqps/sJRnogIS+lq+B1gxxbra2a/w=="], + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.63.0", "", { "os": "linux", "cpu": "none" }, "sha512-aBfOG6fP7YkkPmTqPwufRJeFyz7WPpECv9XNbnsk9+vg7rxdih0lbtEel7jcRng4LZrrmU3FfitCFyEj4BWDWg=="], - "@smithy/smithy-client": ["@smithy/smithy-client@4.9.10", "", { "dependencies": { "@smithy/core": "^3.18.7", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-stack": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-Jaoz4Jw1QYHc1EFww/E6gVtNjhoDU+gwRKqXP6C3LKYqqH2UQhP8tMP3+t/ePrhaze7fhLE8vS2q6vVxBANFTQ=="], + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.63.0", "", { "os": "linux", "cpu": "none" }, "sha512-LGaHEOeHNAag9VuS1Crs5DFg4RrU9MPi2nVnNJk9DTePx/B6RRYKVmrIXt2h7YOJlwjaFJ6lwtFDliZxScTLrQ=="], - "@smithy/types": ["@smithy/types@4.9.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-MvUbdnXDTwykR8cB1WZvNNwqoWVaTRA0RLlLmf/cIFNMM2cKWz01X4Ly6SMC4Kks30r8tT3Cty0jmeWfiuyHTA=="], + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.63.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-jClvk+J0FC3b7Udvegiw5/4hErbHtmsNsQgENnKXDWtNCJXsJYZH5WURvu7imDOO38xYml24eeh5x3A04ppwCw=="], - "@smithy/url-parser": ["@smithy/url-parser@4.2.5", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-VaxMGsilqFnK1CeBX+LXnSuaMx4sTL/6znSZh2829txWieazdVxr54HmiyTsIbpOTLcf5nYpq9lpzmwRdxj6rQ=="], + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.63.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-0OJlaGK+8+B777Ql5okIpD7ua5Ro9+VB9Ve0OKa28OQJZ1RbuUBVNHK/e3pr4BROqsyPl1JrPO1ZxJseCNffcA=="], - "@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="], + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.63.0", "", { "os": "linux", "cpu": "none" }, "sha512-Ygsx+HoNH7afwi1bTIXbnTvVnsO+zurPLSYxybV1hHFVU72OWOCl6v05ql/z0hkpAPx+DK7Kn9Bi7MayCcjLTA=="], - "@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg=="], + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.63.0", "", { "os": "linux", "cpu": "none" }, "sha512-pDQxtMGb+OvG3fLwR2OkZlSd47hW+kWg4BYMG/++sR6RqorQccwPTDsxda5hPwiIeIErAnCF9ma3SAU06bdQtQ=="], - "@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.2.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA=="], + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.63.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-0BnUG9mS8I4SSHr3XsxVhuCMEiu+rX61xxZF5vujso4LaiAGFZFxvDjg6Xn6tLPNTUAfuCvQYas4LMQMVsKRSQ=="], - "@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew=="], + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.63.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Adu/VttB1dpPNW+FEacrZ+xVm9tFty84+RrFzsqlFaPxoJB+9XXyDGtp5dCOoBwGBIEVH0To7lExFXEx0BIF4A=="], - "@smithy/util-config-provider": ["@smithy/util-config-provider@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q=="], + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.63.0", "", { "os": "linux", "cpu": "x64" }, "sha512-NQ3bDvjUbFKmP23671xUlXtKmqVsUBd6M4PQCvbmNtOy06hnQIdKHy8oG/6S3R/S6He1JgPk6A5VT+prAJMYEw=="], - "@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.13", "", { "dependencies": { "@smithy/property-provider": "^4.2.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-hlVLdAGrVfyNei+pKIgqDTxfu/ZI2NSyqj4IDxKd5bIsIqwR/dSlkxlPaYxFiIaDVrBy0he8orsFy+Cz119XvA=="], + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.63.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-u2eDAl4+0aFvA13GxlGBtTI3SS3sdgwgtV0HyjZ0QaQVCgNE+jqNGey+GtxWiq+wxr/UycAx/OnfJzApCFamvA=="], - "@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.16", "", { "dependencies": { "@smithy/config-resolver": "^4.4.3", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-F1t22IUiJLHrxW9W1CQ6B9PN+skZ9cqSuzB18Eh06HrJPbjsyZ7ZHecAKw80DQtyGTRcVfeukKaCRYebFwclbg=="], + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.63.0", "", { "os": "none", "cpu": "arm64" }, "sha512-XvRb5vfW3wAZQ+ZUG21AnHHDKtNcw99eigzEhjr//NZ3u7SoBaPP0seSc7FgP7p1epAEdAoZckMW9WY/+4w70w=="], - "@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.5", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-3O63AAWu2cSNQZp+ayl9I3NapW1p1rR5mlVHcF6hAB1dPZUQFfRPYtplWX/3xrzWthPGj5FqB12taJJCfH6s8A=="], + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.63.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-iZPmniy4kNBf5yo2RezbkYNNK5HPbXE9+g+twnbqSng7dtLEJy1SKoxiE/ni4FDacjyuZpEeb9U054N4EoKHYw=="], - "@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw=="], + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.63.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-mFBBd+LF37fnE8JnYUOH+imj0aPFPK30vpar4ehJkgnLj9sZn8ZxiRENmLtgIwxK7TC8klF6N57fxdNBwQoqOA=="], - "@smithy/util-middleware": ["@smithy/util-middleware@4.2.5", "", { "dependencies": { "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-6Y3+rvBF7+PZOc40ybeZMcGln6xJGVeY60E7jy9Mv5iKpMJpHgRE6dKy9ScsVxvfAYuEX4Q9a65DQX90KaQ3bA=="], + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.63.0", "", { "os": "win32", "cpu": "x64" }, "sha512-ujeqEY3B+zbGn3Z4Q03cUBG/LGWnBJncVT36WER31LcOsQk9+1dmINKKtvmmfChUvRbK1G0R8OhMWFgHgaZtAw=="], - "@smithy/util-retry": ["@smithy/util-retry@4.2.5", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-GBj3+EZBbN4NAqJ/7pAhsXdfzdlznOh8PydUijy6FpNIMnHPSMO2/rP4HKu+UFeikJxShERk528oy7GT79YiJg=="], + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.63.0", "", { "os": "win32", "cpu": "x64" }, "sha512-hncn90N4sOky0L2LKE5oESKLbxCPeVo4eLA2LSMoDzM+879ml4WSr+Rr4DWknNIVVvS1Hirkc9hx02W6YxS8rQ=="], - "@smithy/util-stream": ["@smithy/util-stream@4.5.6", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-qWw/UM59TiaFrPevefOZ8CNBKbYEP6wBAIlLqxn3VAIo9rgnTNc4ASbVrqDmhuwI87usnjhdQrxodzAGFFzbRQ=="], + "@sapphire/async-queue": ["@sapphire/async-queue@1.5.5", "", {}, "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg=="], - "@smithy/util-uri-escape": ["@smithy/util-uri-escape@4.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA=="], + "@sapphire/discord-utilities": ["@sapphire/discord-utilities@4.0.0", "", { "dependencies": { "discord-api-types": "^0.38.30" } }, "sha512-QAvrKNHgswz+ZX48WqSYpRiRzQcugNXXB1C3fR1qbpTJGd7Ckr2OWyFK88TyOksi3U2isrk8sMriTcAgaIe7Qg=="], - "@smithy/util-utf8": ["@smithy/util-utf8@4.2.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw=="], + "@sapphire/discord.js-utilities": ["@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" } }, "sha512-WDj+zjWgNCUSvzYDD0wY3TVeTUseHq0Nhk0wVWxSDjY8z2gFEVcpY7wF8/fbTDWP44LUG5sUQ4haIrIj2OjmkQ=="], - "@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="], + "@sapphire/duration": ["@sapphire/duration@1.2.0", "", {}, "sha512-LxjOAFXz81WmrI8XX9YaVcAZDjQj/1p78lZCvkAWZB1nphOwz/D0dU3CBejmhOWx5dO5CszTkLJMNR0xuCK+Zg=="], - "@tootallnate/once": ["@tootallnate/once@2.0.1", "", {}, "sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ=="], + "@sapphire/framework": ["@sapphire/framework@5.5.1", "", { "dependencies": { "@discordjs/builders": "^1.13.0", "@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" } }, "sha512-UlEoj3XRjSyGJg1+kD43q5YHfmDDJ1fNN5Ws3OifvgMNhnOrrL1diTjU1ALfLrfUbPuBCJWD1ZfIj/i/J4K9eQ=="], - "@types/caseless": ["@types/caseless@0.12.5", "", {}, "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg=="], + "@sapphire/lexure": ["@sapphire/lexure@1.1.12", "", { "dependencies": { "@sapphire/result": "^2.8.0" } }, "sha512-F7Z3QzRnAZGunRl24/qQMhzRogZU/foumu2EBBunRnQi/o/DLTCwdAbLgJATyPlvJa8N6FrJq0JJwvzM/vXoXg=="], - "@types/jsonwebtoken": ["@types/jsonwebtoken@9.0.10", "", { "dependencies": { "@types/ms": "*", "@types/node": "*" } }, "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA=="], + "@sapphire/pieces": ["@sapphire/pieces@4.4.1", "", { "dependencies": { "@discordjs/collection": "^2.1.1", "@sapphire/utilities": "^3.18.2", "tslib": "^2.8.1" } }, "sha512-2v49P++RzHGb23bdjSa9u7flkdvhrq94IUO9PneY538TILN5QiMxfaXVK+pDR2YR7jpQYBy9APwtFDes2Svykg=="], - "@types/long": ["@types/long@4.0.2", "", {}, "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA=="], + "@sapphire/plugin-editable-commands": ["@sapphire/plugin-editable-commands@4.0.4", "", { "dependencies": { "@skyra/editable-commands": "^3.0.4" } }, "sha512-1Dd04IjZxYjPWupMJPAyOupWUvYNkhOAUdWhoIBRDRjy6eytOHYYD5TpH8QLXsfgbQNV/ETdWDG0IBVH/Vg/EA=="], - "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], + "@sapphire/ratelimits": ["@sapphire/ratelimits@2.4.11", "", {}, "sha512-O6FNA/P0wxU4Ve9gxL948CoZw7+sSpujyUR2CLyLLCNuNvuFGFxPCJVl5crFVLXMIyBIrc2qk+/H9bsqsyQK1Q=="], - "@types/node": ["@types/node@24.10.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-WOhQTZ4G8xZ1tjJTvKOpyEVSGgOTvJAfDK3FNFgELyaTpzhdgHVHeqW8V+UJvzF5BT+/B54T/1S2K6gd9c7bbA=="], + "@sapphire/result": ["@sapphire/result@2.8.0", "", {}, "sha512-693yWouX+hR9uJm1Jgq0uSSjbSD3UrblMaxiuGbHPjSwzLCSZTcm0h3kvdVhq3o/yl4+oeAWW3hiaJ0TELuRJQ=="], - "@types/request": ["@types/request@2.48.13", "", { "dependencies": { "@types/caseless": "*", "@types/node": "*", "@types/tough-cookie": "*", "form-data": "^2.5.5" } }, "sha512-FGJ6udDNUCjd19pp0Q3iTiDkwhYup7J8hpMW9c4k53NrccQFFWKRho6hvtPPEhnXWKvukfwAlB6DbDz4yhH5Gg=="], + "@sapphire/shapeshift": ["@sapphire/shapeshift@4.0.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "lodash": "^4.17.21" } }, "sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg=="], - "@types/tough-cookie": ["@types/tough-cookie@4.0.5", "", {}, "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA=="], + "@sapphire/snowflake": ["@sapphire/snowflake@3.5.5", "", {}, "sha512-xzvBr1Q1c4lCe7i6sRnrofxeO1QTP/LKQ6A6qy0iB4x5yfiSfARMEQEghojzTNALDTcv8En04qYNIco9/K9eZQ=="], - "@types/webidl-conversions": ["@types/webidl-conversions@7.0.3", "", {}, "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA=="], + "@sapphire/stopwatch": ["@sapphire/stopwatch@1.5.4", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-IVI48D2yAz411bSttXyTkBH0p2vhrXoqWLn5loDDSAAEUGkM1r5KNCX2027ifQ8svdoMkUfIGjFueR+satLeWw=="], - "@types/whatwg-url": ["@types/whatwg-url@8.2.2", "", { "dependencies": { "@types/node": "*", "@types/webidl-conversions": "*" } }, "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA=="], + "@sapphire/utilities": ["@sapphire/utilities@3.18.2", "", {}, "sha512-QGLdC9+pT74Zd7aaObqn0EUfq40c4dyTL65pFnkM6WO1QYN7Yg/s4CdH+CXmx0Zcu6wcfCWILSftXPMosJHP5A=="], - "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], + "@skyra/editable-commands": ["@skyra/editable-commands@3.0.4", "", {}, "sha512-wQQqOt/GVnKTY0yfL9AmBCvoNIRa/4COxMDYS/TcQexabdZlIfxG4up2zKz8A1or5+73meDZ/D/SvUav36/V2w=="], - "@vladfrangu/async_event_emitter": ["@vladfrangu/async_event_emitter@2.4.7", "", {}, "sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g=="], + "@smithy/core": ["@smithy/core@3.33.3", "", { "dependencies": { "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-CsOeKq/9kA3y6VJHt+/+VTCtBaxJ4OTFpgrjIUhPpDIKxBci1k2bJaQASF2h/ELWrulGp+t97DZ0mevfAD8idg=="], - "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], + "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.5.2", "", { "dependencies": { "@smithy/core": "^3.33.2", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg=="], - "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], + "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.7.2", "", { "dependencies": { "@smithy/core": "^3.33.2", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-nZyWTmSpJEXl6VtWVMBJve/7x12DZu6sIX1z1a+ZMaHlQQRs9Zpu6NbTe/gmxYXVRpkjxyDYpZ5gx2IM6f/Wkw=="], - "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "@smithy/node-http-handler": ["@smithy/node-http-handler@4.11.3", "", { "dependencies": { "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-2jY1tSpERfPfWqyBV2pH+iGFaghVsIJszJNsT7hxtQYhVJpWDyc0LqOWI+nXOxOAHaEfZ4PXXtp1wW1TGpHhkA=="], - "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "@smithy/signature-v4": ["@smithy/signature-v4@5.7.3", "", { "dependencies": { "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-7ImGm+FkHRLcBaRttIAMZ6bzJZWb2cJGoYjq46F2UjycujWzrL9GEN9h4w7eQyXJYnltrUhxbbieBAIRrdqpow=="], - "arrify": ["arrify@2.0.1", "", {}, "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug=="], + "@smithy/types": ["@smithy/types@4.17.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-FOKpVZob9MPTn2znRzGrnsMHv7BOsKVw3XiP/cOyYLDVZ9qKp4nifIiSCuUU/fIj5Vu0UOAxCFr+qRAtG0NUkA=="], - "async-retry": ["async-retry@1.3.3", "", { "dependencies": { "retry": "0.13.1" } }, "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw=="], + "@types/esrecurse": ["@types/esrecurse@4.3.1", "", {}, "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw=="], - "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], + "@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="], - "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], - "bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="], + "@types/node": ["@types/node@26.3.0", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-L3fgrnchriRC2ExBflb8j4uZZURHZfQsmQeyVzhjcHW4kkwVyo8/0h1B2MVzMTrYUJYu6G7EWs14hW/L9putqw=="], - "bowser": ["bowser@2.13.1", "", {}, "sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw=="], + "@types/webidl-conversions": ["@types/webidl-conversions@7.0.3", "", {}, "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA=="], - "bson": ["bson@4.7.2", "", { "dependencies": { "buffer": "^5.6.0" } }, "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ=="], + "@types/whatwg-url": ["@types/whatwg-url@8.2.2", "", { "dependencies": { "@types/node": "*", "@types/webidl-conversions": "*" } }, "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA=="], - "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], + "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], - "buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="], + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.69.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.69.0", "@typescript-eslint/type-utils": "8.69.0", "@typescript-eslint/utils": "8.69.0", "@typescript-eslint/visitor-keys": "8.69.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.69.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-t5jQTKPIgVW1PE6dR6H6Qz5gm8zjMlX5/2gRaOGd9eO6V7J+tQc6iWKukEe7dY8u9HyYasQ0yfF0/FSSTEO2gA=="], - "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.69.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.69.0", "@typescript-eslint/types": "8.69.0", "@typescript-eslint/typescript-estree": "8.69.0", "@typescript-eslint/visitor-keys": "8.69.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-l4b0DhWioGg6Gt2ebGlvfkFMOjRsauxtsnDRwUSRX1qHq3HdTfQHV8wW9zEXeciai6HfeaKOedQn2Zoofx3WBw=="], - "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.69.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.69.0", "@typescript-eslint/types": "^8.69.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-yi4obFrHMmnsesWehHbkg9zMA7Jt8cXT+mKM08G999pH1yT6nqgsHx7MYm0uY1wAj8CqiBXYRJ7WAT0QdQHQXg=="], - "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.69.0", "", { "dependencies": { "@typescript-eslint/types": "8.69.0", "@typescript-eslint/visitor-keys": "8.69.0" } }, "sha512-ewfspqWvSxKSOaplqAUNbaSFO0eB6w1EtQ+esfYFRm3614Ty4uNtExkcbgd6nWsXphbqKyf9ZYdbZdv2xEoWEQ=="], - "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.69.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-xNqK7YTDZsLniQMV/4rpFR8Z5JlqeRvVjuG1YgF/mdPVH84HSD19L8CczMA0qg2RfwEV231GHH3VnToJDo4MfQ=="], - "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.69.0", "", { "dependencies": { "@typescript-eslint/types": "8.69.0", "@typescript-eslint/typescript-estree": "8.69.0", "@typescript-eslint/utils": "8.69.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-ZfoJAVg3JZndQEpEl9petVlxau3lRuElc4HRMuAlLCf8to04/iHz692RUSNmXKDjEuJmIL+KZ2/BsOcBc16dsA=="], - "data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="], + "@typescript-eslint/types": ["@typescript-eslint/types@8.69.0", "", {}, "sha512-K3VrubUPhlo9VDBS6QdI8YB5j7ClpqLRdefcz6PFrhnwicehBweqQ9Evhl4l+FYz0HdDmMqIiSX0aldGRYtDCA=="], - "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.69.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.69.0", "@typescript-eslint/tsconfig-utils": "8.69.0", "@typescript-eslint/types": "8.69.0", "@typescript-eslint/visitor-keys": "8.69.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-AdFkgqck3Vudb/kWnxlyafU/4aBhHrbQ9locP2N4psXTy5mOBg0SHJumnLvx7r6g1gV4DKvUFwV2nJZBoqOD8w=="], - "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.69.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.69.0", "@typescript-eslint/types": "8.69.0", "@typescript-eslint/typescript-estree": "8.69.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-tUbx60BBqQa31kXF5MCsOOLL5E/WzUuxIn7YpAvq+eaUlqvk8/NXnXMBNAdLCr0icjkzem7iUA5QqWHe/hJ1aw=="], - "discord-api-types": ["discord-api-types@0.38.36", "", {}, "sha512-qrbUbjjwtyeBg5HsAlm1C859epfOyiLjPqAOzkdWlCNsZCWJrertnETF/NwM8H+waMFU58xGSc5eXUfXah+WTQ=="], + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.69.0", "", { "dependencies": { "@typescript-eslint/types": "8.69.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-+rmdgPA+EXkNgKYvHvFfhrs35utXbwaC5PGpDquSXcoXQDKUA5UjV0LmTucG/4JXkM31BTu4TilHtrN8IVBe8w=="], - "discord.js": ["discord.js@14.25.1", "", { "dependencies": { "@discordjs/builders": "^1.13.0", "@discordjs/collection": "1.5.3", "@discordjs/formatters": "^0.6.2", "@discordjs/rest": "^2.6.0", "@discordjs/util": "^1.2.0", "@discordjs/ws": "^1.2.3", "@sapphire/snowflake": "3.5.3", "discord-api-types": "^0.38.33", "fast-deep-equal": "3.1.3", "lodash.snakecase": "4.1.1", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", "undici": "6.21.3" } }, "sha512-2l0gsPOLPs5t6GFZfQZKnL1OJNYFcuC/ETWsW4VtKVD/tg4ICa9x+jb9bkPffkMdRpRpuUaO/fKkHCBeiCKh8g=="], + "@vladfrangu/async_event_emitter": ["@vladfrangu/async_event_emitter@2.4.7", "", {}, "sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g=="], - "dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], + "acorn": ["acorn@8.18.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ=="], - "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], - "duplexify": ["duplexify@4.1.3", "", { "dependencies": { "end-of-stream": "^1.4.1", "inherits": "^2.0.3", "readable-stream": "^3.1.1", "stream-shift": "^1.0.2" } }, "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA=="], + "ajv": ["ajv@6.15.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw=="], - "ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="], + "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], - "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], - "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], - "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + "bowser": ["bowser@2.14.1", "", {}, "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg=="], - "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + "brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="], - "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + "bson": ["bson@4.7.2", "", { "dependencies": { "buffer": "^5.6.0" } }, "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ=="], - "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], + "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], - "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + "bundle-require": ["bundle-require@5.1.0", "", { "dependencies": { "load-tsconfig": "^0.2.3" }, "peerDependencies": { "esbuild": ">=0.18" } }, "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA=="], - "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="], + "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], - "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], + "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], - "farmhash-modern": ["farmhash-modern@1.1.0", "", {}, "sha512-6ypT4XfgqJk/F3Yuv4SX26I3doUjt0GTG4a+JgWxXQpxXzTBq8fPUeGHfcYMMDPHJHm3yPOSjaeBwBGAHWXCdA=="], + "commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], - "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], - "fast-xml-builder": ["fast-xml-builder@1.1.8", "", { "dependencies": { "path-expression-matcher": "^1.1.3" } }, "sha512-sDVBc2gg8pSKvcbE8rBmOyjSGQf0AdsbqvHeIOv3D/uYNoV4eCReQXyDF8Pdv8+m1FHazACypSz2hR7O2S1LLw=="], + "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], - "fast-xml-parser": ["fast-xml-parser@5.7.3", "", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.1.7", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg=="], + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], - "faye-websocket": ["faye-websocket@0.11.4", "", { "dependencies": { "websocket-driver": ">=0.5.1" } }, "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g=="], + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], - "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="], + "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], - "firebase-admin": ["firebase-admin@13.8.0", "", { "dependencies": { "@fastify/busboy": "^3.0.0", "@firebase/database-compat": "^2.0.0", "@firebase/database-types": "^1.0.6", "farmhash-modern": "^1.1.0", "fast-deep-equal": "^3.1.1", "google-auth-library": "^10.6.1", "jsonwebtoken": "^9.0.0", "jwks-rsa": "^3.1.0", "node-forge": "^1.4.0", "uuid": "^11.0.2" }, "optionalDependencies": { "@google-cloud/firestore": "^7.11.0", "@google-cloud/storage": "^7.19.0" } }, "sha512-iawoQkmZbsA+2DY5UEuB8f6jSlskzzySoye0D2F6e3zlDZX9DUcXf0HhZqLUn/P6WhLGvTf6ZtCmshZvhAgTYg=="], + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], - "form-data": ["form-data@2.5.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.35", "safe-buffer": "^5.2.1" } }, "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A=="], + "discord-api-types": ["discord-api-types@0.38.53", "", {}, "sha512-HL1zz/UuZ+bbJjA/X8Kbxx9gk8v9rJAbTeWRNYKmIdjwJ7EovjlHgoJTxcLpATfNJ+AonOtMdy3Y5MVIJAAd/A=="], - "formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="], + "discord.js": ["discord.js@14.27.0", "", { "dependencies": { "@discordjs/builders": "^1.14.1", "@discordjs/collection": "1.5.3", "@discordjs/formatters": "^0.6.2", "@discordjs/rest": "^2.6.2", "@discordjs/util": "^1.2.0", "@discordjs/ws": "^1.2.3", "@sapphire/snowflake": "3.5.5", "discord-api-types": "^0.38.49", "fast-deep-equal": "3.1.3", "lodash.snakecase": "4.1.1", "magic-bytes.js": "^1.13.0", "tslib": "^2.6.3", "undici": "^6.27.0" } }, "sha512-qHbFlFG2N7y3LjPySYsL6A1+BnX6bkTVgo842EX0CqVPk/KTMwZkojPHEXKsQUpWZNyz5BISNHK1cPpQw0+m4A=="], - "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + "dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], - "functional-red-black-tree": ["functional-red-black-tree@1.0.1", "", {}, "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g=="], + "esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="], - "gaxios": ["gaxios@6.7.1", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", "node-fetch": "^2.6.9", "uuid": "^9.0.1" } }, "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ=="], + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], - "gcp-metadata": ["gcp-metadata@8.1.2", "", { "dependencies": { "gaxios": "^7.0.0", "google-logging-utils": "^1.0.0", "json-bigint": "^1.0.0" } }, "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg=="], + "eslint": ["eslint@10.9.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", "@eslint/config-array": "^0.23.5", "@eslint/config-helpers": "^0.7.0", "@eslint/core": "^1.2.1", "@eslint/plugin-kit": "^0.7.2", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^9.1.2", "eslint-visitor-keys": "^5.0.1", "espree": "^11.2.0", "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "minimatch": "^10.2.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-9VaAkDURekixUQJy0oJYl2DcN6oKMfxay7XzaGYAWQwsb6qfKf+x76R2k1L8kb1boc+FyCAaTA9GmiKaaiaF+A=="], - "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + "eslint-scope": ["eslint-scope@9.1.2", "", { "dependencies": { "@types/esrecurse": "^4.3.1", "@types/estree": "^1.0.8", "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ=="], - "get-intrinsic": ["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.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + "eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], - "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + "espree": ["espree@11.2.0", "", { "dependencies": { "acorn": "^8.16.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^5.0.1" } }, "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw=="], - "google-auth-library": ["google-auth-library@10.6.2", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.1.4", "gcp-metadata": "8.1.2", "google-logging-utils": "1.1.3", "jws": "^4.0.0" } }, "sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw=="], + "esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="], - "google-gax": ["google-gax@4.6.1", "", { "dependencies": { "@grpc/grpc-js": "^1.10.9", "@grpc/proto-loader": "^0.7.13", "@types/long": "^4.0.0", "abort-controller": "^3.0.0", "duplexify": "^4.0.0", "google-auth-library": "^9.3.0", "node-fetch": "^2.7.0", "object-hash": "^3.0.0", "proto3-json-serializer": "^2.0.2", "protobufjs": "^7.3.2", "retry-request": "^7.0.0", "uuid": "^9.0.1" } }, "sha512-V6eky/xz2mcKfAd1Ioxyd6nmA61gao3n01C+YeuIwu3vzM9EDR6wcVzMSIbLMDXWeoi9SHYctXuKYC5uJUT3eQ=="], + "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], - "google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="], + "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], - "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], - "gtoken": ["gtoken@7.1.0", "", { "dependencies": { "gaxios": "^6.0.0", "jws": "^4.0.0" } }, "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw=="], + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], - "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], - "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], + "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], - "hasown": ["hasown@2.0.3", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg=="], + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], - "html-entities": ["html-entities@2.6.0", "", {}, "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ=="], + "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], - "http-parser-js": ["http-parser-js@0.5.10", "", {}, "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA=="], + "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], - "http-proxy-agent": ["http-proxy-agent@5.0.0", "", { "dependencies": { "@tootallnate/once": "2", "agent-base": "6", "debug": "4" } }, "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w=="], + "fix-dts-default-cjs-exports": ["fix-dts-default-cjs-exports@1.0.1", "", { "dependencies": { "magic-string": "^0.30.17", "mlly": "^1.7.4", "rollup": "^4.34.8" } }, "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg=="], - "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], + "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], - "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "flatted": ["flatted@3.4.4", "", {}, "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q=="], - "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - "ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="], + "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], - "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], - "jose": ["jose@4.15.9", "", {}, "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA=="], + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], - "json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="], + "ip-address": ["ip-address@10.5.0", "", {}, "sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g=="], - "jsonwebtoken": ["jsonwebtoken@9.0.3", "", { "dependencies": { "jws": "^4.0.1", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", "lodash.isnumber": "^3.0.3", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^7.5.4" } }, "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g=="], + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], - "jwa": ["jwa@2.0.1", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="], + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], - "jwks-rsa": ["jwks-rsa@3.2.2", "", { "dependencies": { "@types/jsonwebtoken": "^9.0.4", "debug": "^4.3.4", "jose": "^4.15.4", "limiter": "^1.1.5", "lru-memoizer": "^2.2.0" } }, "sha512-BqTyEDV+lS8F2trk3A+qJnxV5Q9EqKCBJOPti3W97r7qTympCZjb7h2X6f2kc+0K3rsSTY1/6YG2eaXKoj497w=="], + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], - "jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="], + "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="], - "kareem": ["kareem@2.5.1", "", {}, "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA=="], + "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], - "limiter": ["limiter@1.1.5", "", {}, "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA=="], + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], - "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], + "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], - "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="], + "kareem": ["kareem@2.5.1", "", {}, "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA=="], - "lodash.clonedeep": ["lodash.clonedeep@4.5.0", "", {}, "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ=="], + "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], - "lodash.includes": ["lodash.includes@4.3.0", "", {}, "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="], + "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], - "lodash.isboolean": ["lodash.isboolean@3.0.3", "", {}, "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="], + "lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="], - "lodash.isinteger": ["lodash.isinteger@4.0.4", "", {}, "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="], + "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], - "lodash.isnumber": ["lodash.isnumber@3.0.3", "", {}, "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="], + "lmdb": ["lmdb@3.5.6", "", { "dependencies": { "@harperfast/extended-iterable": "^1.0.3", "msgpackr": "^1.11.2", "node-addon-api": "^6.1.0", "node-gyp-build-optional-packages": "5.2.2", "ordered-binary": "^1.5.3", "weak-lru-cache": "^1.2.2" }, "optionalDependencies": { "@lmdb/lmdb-darwin-arm64": "3.5.6", "@lmdb/lmdb-darwin-x64": "3.5.6", "@lmdb/lmdb-linux-arm": "3.5.6", "@lmdb/lmdb-linux-arm64": "3.5.6", "@lmdb/lmdb-linux-x64": "3.5.6", "@lmdb/lmdb-win32-arm64": "3.5.6", "@lmdb/lmdb-win32-x64": "3.5.6" }, "bin": { "download-lmdb-prebuilds": "bin/download-prebuilds.js" } }, "sha512-j3uE8ReKNyUWDjhfEFSJqE/1DLtfTR5Z8yFzVHvBjAk37wNg7HdScjcv8ttPHRvrdgPQMPWxFFI0SsdBzI5lBw=="], - "lodash.isplainobject": ["lodash.isplainobject@4.0.6", "", {}, "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="], + "load-tsconfig": ["load-tsconfig@0.2.5", "", {}, "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg=="], - "lodash.isstring": ["lodash.isstring@4.0.1", "", {}, "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="], + "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], - "lodash.once": ["lodash.once@4.1.1", "", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="], + "lodash": ["lodash@4.18.1", "", {}, "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q=="], "lodash.snakecase": ["lodash.snakecase@4.1.1", "", {}, "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw=="], - "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], - - "lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], + "magic-bytes.js": ["magic-bytes.js@1.13.1", "", {}, "sha512-x5sn4UX2k5gCWlcfmoFwG4TPie8+dctESyqOBdhB5p6MsgWXdBKGmt9nXPObj/JI50TTL928lc5Yt1WntMn1bw=="], - "lru-memoizer": ["lru-memoizer@2.3.0", "", { "dependencies": { "lodash.clonedeep": "^4.5.0", "lru-cache": "6.0.0" } }, "sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug=="], - - "magic-bytes.js": ["magic-bytes.js@1.12.1", "", {}, "sha512-ThQLOhN86ZkJ7qemtVRGYM+gRgR8GEXNli9H/PMvpnZsE44Xfh3wx9kGJaldg314v85m+bFW6WBMaVHJc/c3zA=="], - - "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], "memory-pager": ["memory-pager@1.5.0", "", {}, "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg=="], - "mime": ["mime@3.0.0", "", { "bin": "cli.js" }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="], - - "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + "minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" } }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="], - "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "mlly": ["mlly@1.8.2", "", { "dependencies": { "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.3" } }, "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA=="], "mongodb": ["mongodb@4.17.2", "", { "dependencies": { "bson": "^4.7.2", "mongodb-connection-string-url": "^2.6.0", "socks": "^2.7.1" }, "optionalDependencies": { "@aws-sdk/credential-providers": "^3.186.0", "@mongodb-js/saslprep": "^1.1.0" } }, "sha512-mLV7SEiov2LHleRJPMPrK2PMyhXFZt2UQLC4VD4pnth3jMjYKHhtqfwwkkvS/NXuo/Fp3vbhaNcXrIDaLRb9Tg=="], "mongodb-connection-string-url": ["mongodb-connection-string-url@2.6.0", "", { "dependencies": { "@types/whatwg-url": "^8.2.1", "whatwg-url": "^11.0.0" } }, "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ=="], - "mongoose": ["mongoose@6.13.8", "", { "dependencies": { "bson": "^4.7.2", "kareem": "2.5.1", "mongodb": "4.17.2", "mpath": "0.9.0", "mquery": "4.0.3", "ms": "2.1.3", "sift": "16.0.1" } }, "sha512-JHKco/533CyVrqCbyQsnqMpLn8ZCiKrPDTd2mvo2W7ygIvhygWjX2wj+RPjn6upZZgw0jC6U51RD7kUsyK8NBg=="], + "mongoose": ["mongoose@6.13.11", "", { "dependencies": { "bson": "^4.7.2", "kareem": "2.5.1", "mongodb": "4.17.2", "mpath": "0.9.0", "mquery": "4.0.3", "ms": "2.1.3", "sift": "16.0.1" } }, "sha512-5KM1Oq106FCdiy4//geOam3mPFekkSY0a4L+zQQPrc6tB6AJtg772aMgeUHF2sTNSxFhJQsAOjpLJpK6Cz+hRw=="], "mpath": ["mpath@0.9.0", "", {}, "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew=="], @@ -470,166 +464,134 @@ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], + "msgpackr": ["msgpackr@1.12.1", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, "sha512-4EUH9tQHnMmEgzW/MdAP0KIfa1T9AF+htl0ffe2n5vb2EKn9y2co8ccpgWko6S52Jy1PQZKwRnx5/KkYjtd9MQ=="], - "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + "msgpackr-extract": ["msgpackr-extract@3.0.4", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw=="], - "node-forge": ["node-forge@1.4.0", "", {}, "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ=="], + "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], - "object-hash": ["object-hash@3.0.0", "", {}, "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw=="], + "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], - "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], - - "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], + "node-addon-api": ["node-addon-api@6.1.0", "", {}, "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA=="], - "parse-ms": ["parse-ms@3.0.0", "", {}, "sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw=="], + "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="], - "path-expression-matcher": ["path-expression-matcher@1.5.0", "", {}, "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ=="], + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], - "prettier": ["prettier@3.8.1", "", { "bin": "bin/prettier.cjs" }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="], + "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], - "pretty-ms": ["pretty-ms@8.0.0", "", { "dependencies": { "parse-ms": "^3.0.0" } }, "sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q=="], + "ordered-binary": ["ordered-binary@1.6.1", "", {}, "sha512-QkCdPooczexPLiXIrbVOPYkR3VO3T6v2OyKRkR1Xbhpy7/LAVXwahnRCgRp78Oe/Ehf0C/HATAxfSr6eA1oX+w=="], - "proto3-json-serializer": ["proto3-json-serializer@2.0.2", "", { "dependencies": { "protobufjs": "^7.2.5" } }, "sha512-SAzp/O4Yh02jGdRc+uIrGoe87dkN/XtwxfZ4ZyafJHymd79ozp5VG5nyZ7ygqPM5+cpLDjjGnYFUkngonyDPOQ=="], - - "protobufjs": ["protobufjs@7.5.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg=="], - - "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], - - "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], - - "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], - - "retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], - - "retry-request": ["retry-request@7.0.2", "", { "dependencies": { "@types/request": "^2.48.8", "extend": "^3.0.2", "teeny-request": "^9.0.0" } }, "sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w=="], - - "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], - - "semver": ["semver@7.7.4", "", { "bin": "bin/semver.js" }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - - "sift": ["sift@16.0.1", "", {}, "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ=="], - - "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], - - "socks": ["socks@2.8.7", "", { "dependencies": { "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" } }, "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A=="], - - "sparse-bitfield": ["sparse-bitfield@3.0.3", "", { "dependencies": { "memory-pager": "^1.0.2" } }, "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ=="], - - "stream-events": ["stream-events@1.0.5", "", { "dependencies": { "stubs": "^3.0.0" } }, "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg=="], - - "stream-shift": ["stream-shift@1.0.3", "", {}, "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ=="], - - "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], - "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], - "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], - "strnum": ["strnum@2.2.3", "", {}, "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg=="], + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], - "stubs": ["stubs@3.0.0", "", {}, "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw=="], + "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "teeny-request": ["teeny-request@9.0.0", "", { "dependencies": { "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "node-fetch": "^2.6.9", "stream-events": "^1.0.5", "uuid": "^9.0.0" } }, "sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g=="], + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - "tr46": ["tr46@3.0.0", "", { "dependencies": { "punycode": "^2.1.1" } }, "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA=="], + "picomatch": ["picomatch@4.0.7", "", {}, "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA=="], - "ts-mixer": ["ts-mixer@6.0.4", "", {}, "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA=="], + "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], - "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], - "undici": ["undici@6.21.3", "", {}, "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw=="], + "postcss-load-config": ["postcss-load-config@6.0.1", "", { "dependencies": { "lilconfig": "^3.1.1" }, "peerDependencies": { "jiti": ">=1.21.0", "postcss": ">=8.0.9", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["jiti", "postcss", "tsx", "yaml"] }, "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g=="], - "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], - "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + "prettier": ["prettier@3.9.6", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g=="], - "uuid": ["uuid@11.1.1", "", { "bin": "dist/esm/bin/uuid" }, "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ=="], + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], - "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], + "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], - "webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="], + "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], - "websocket-driver": ["websocket-driver@0.7.4", "", { "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", "websocket-extensions": ">=0.1.1" } }, "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg=="], + "rollup": ["rollup@4.63.0", "", { "dependencies": { "@types/estree": "1.0.9" }, "optionalDependencies": { "@napi-rs/lzma-linux-x64-gnu": "1.5.1", "@rollup/rollup-android-arm-eabi": "4.63.0", "@rollup/rollup-android-arm64": "4.63.0", "@rollup/rollup-darwin-arm64": "4.63.0", "@rollup/rollup-darwin-x64": "4.63.0", "@rollup/rollup-freebsd-arm64": "4.63.0", "@rollup/rollup-freebsd-x64": "4.63.0", "@rollup/rollup-linux-arm-gnueabihf": "4.63.0", "@rollup/rollup-linux-arm-musleabihf": "4.63.0", "@rollup/rollup-linux-arm64-gnu": "4.63.0", "@rollup/rollup-linux-arm64-musl": "4.63.0", "@rollup/rollup-linux-loong64-gnu": "4.63.0", "@rollup/rollup-linux-loong64-musl": "4.63.0", "@rollup/rollup-linux-ppc64-gnu": "4.63.0", "@rollup/rollup-linux-ppc64-musl": "4.63.0", "@rollup/rollup-linux-riscv64-gnu": "4.63.0", "@rollup/rollup-linux-riscv64-musl": "4.63.0", "@rollup/rollup-linux-s390x-gnu": "4.63.0", "@rollup/rollup-linux-x64-gnu": "4.63.0", "@rollup/rollup-linux-x64-musl": "4.63.0", "@rollup/rollup-openbsd-x64": "4.63.0", "@rollup/rollup-openharmony-arm64": "4.63.0", "@rollup/rollup-win32-arm64-msvc": "4.63.0", "@rollup/rollup-win32-ia32-msvc": "4.63.0", "@rollup/rollup-win32-x64-gnu": "4.63.0", "@rollup/rollup-win32-x64-msvc": "4.63.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-T5vnZ2y4QqC3/4P+w2+JO+Q/OVdnPsv4XcSYJYMEn0R9/jjl5AgLwO9LAZMzP2lN71O6pypn91rB7lDstUkfrQ=="], - "websocket-extensions": ["websocket-extensions@0.1.4", "", {}, "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg=="], + "semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], - "whatwg-url": ["whatwg-url@11.0.0", "", { "dependencies": { "tr46": "^3.0.0", "webidl-conversions": "^7.0.0" } }, "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ=="], + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], - "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], - "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + "sift": ["sift@16.0.1", "", {}, "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ=="], - "ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], + "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], - "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + "socks": ["socks@2.8.9", "", { "dependencies": { "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" } }, "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw=="], - "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], - "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + "sparse-bitfield": ["sparse-bitfield@3.0.3", "", { "dependencies": { "memory-pager": "^1.0.2" } }, "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ=="], - "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + "sucrase": ["sucrase@3.35.1", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw=="], - "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="], - "@aws-crypto/sha256-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], + "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], - "@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], + "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], - "@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], + "tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], - "@discordjs/rest/@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="], + "tr46": ["tr46@3.0.0", "", { "dependencies": { "punycode": "^2.1.1" } }, "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA=="], - "@discordjs/ws/@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="], + "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], - "@google-cloud/storage/google-auth-library": ["google-auth-library@9.15.1", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^6.1.1", "gcp-metadata": "^6.1.0", "gtoken": "^7.0.0", "jws": "^4.0.0" } }, "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng=="], + "ts-api-utils": ["ts-api-utils@2.5.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA=="], - "@google-cloud/storage/uuid": ["uuid@8.3.2", "", { "bin": "dist/bin/uuid" }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], - "@grpc/grpc-js/@grpc/proto-loader": ["@grpc/proto-loader@0.8.0", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.5.3", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ=="], + "ts-mixer": ["ts-mixer@6.0.4", "", {}, "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA=="], - "gaxios/uuid": ["uuid@9.0.1", "", { "bin": "dist/bin/uuid" }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "gcp-metadata/gaxios": ["gaxios@7.1.4", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2" } }, "sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA=="], + "tsup": ["tsup@8.5.1", "", { "dependencies": { "bundle-require": "^5.1.0", "cac": "^6.7.14", "chokidar": "^4.0.3", "consola": "^3.4.0", "debug": "^4.4.0", "esbuild": "^0.27.0", "fix-dts-default-cjs-exports": "^1.0.0", "joycon": "^3.1.1", "picocolors": "^1.1.1", "postcss-load-config": "^6.0.1", "resolve-from": "^5.0.0", "rollup": "^4.34.8", "source-map": "^0.7.6", "sucrase": "^3.35.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.11", "tree-kill": "^1.2.2" }, "peerDependencies": { "@microsoft/api-extractor": "^7.36.0", "@swc/core": "^1", "postcss": "^8.4.12", "typescript": ">=4.5.0" }, "optionalPeers": ["@microsoft/api-extractor", "@swc/core", "postcss", "typescript"], "bin": { "tsup": "dist/cli-default.js", "tsup-node": "dist/cli-node.js" } }, "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing=="], - "google-auth-library/gaxios": ["gaxios@7.1.4", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2" } }, "sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA=="], + "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], - "google-gax/google-auth-library": ["google-auth-library@9.15.1", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^6.1.1", "gcp-metadata": "^6.1.0", "gtoken": "^7.0.0", "jws": "^4.0.0" } }, "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng=="], + "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], - "google-gax/uuid": ["uuid@9.0.1", "", { "bin": "dist/bin/uuid" }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], + "typescript-eslint": ["typescript-eslint@8.69.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.69.0", "@typescript-eslint/parser": "8.69.0", "@typescript-eslint/typescript-estree": "8.69.0", "@typescript-eslint/utils": "8.69.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-B3MltX0VqjUBNEe3b3sSuiRbfa6XrfHFtBiPamjT5AsW/dfq+y+bc0wyuS9DxAS1LyzCxRp2+rxzpLUvqM2BvA=="], - "http-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="], + "ufo": ["ufo@1.6.4", "", {}, "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA=="], - "node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], + "undici": ["undici@6.28.0", "", {}, "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA=="], - "teeny-request/https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="], + "undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="], - "teeny-request/uuid": ["uuid@9.0.1", "", { "bin": "dist/bin/uuid" }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], - "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], + "weak-lru-cache": ["weak-lru-cache@1.2.2", "", {}, "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw=="], - "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], + "webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="], - "@google-cloud/storage/google-auth-library/gcp-metadata": ["gcp-metadata@6.1.1", "", { "dependencies": { "gaxios": "^6.1.1", "google-logging-utils": "^0.0.2", "json-bigint": "^1.0.0" } }, "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A=="], + "whatwg-url": ["whatwg-url@11.0.0", "", { "dependencies": { "tr46": "^3.0.0", "webidl-conversions": "^7.0.0" } }, "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ=="], - "gcp-metadata/gaxios/node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], - "google-auth-library/gaxios/node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], + "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], - "google-gax/google-auth-library/gcp-metadata": ["gcp-metadata@6.1.1", "", { "dependencies": { "gaxios": "^6.1.1", "google-logging-utils": "^0.0.2", "json-bigint": "^1.0.0" } }, "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A=="], + "ws": ["ws@8.21.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw=="], - "node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - "node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + "@discordjs/rest/@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="], - "teeny-request/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="], + "@discordjs/ws/@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="], - "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], + "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], - "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], + "@sapphire/discord.js-utilities/@sapphire/discord-utilities": ["@sapphire/discord-utilities@3.5.0", "", { "dependencies": { "discord-api-types": "^0.38.1" } }, "sha512-H4SY5KTVDZrqA5QG7ob6etwqhdOb3TRSY2wv56f0tiobUdIr0irlrYvdmr8Kg/FRxWU+aiHDIISWGG5vBuxOGw=="], - "@google-cloud/storage/google-auth-library/gcp-metadata/google-logging-utils": ["google-logging-utils@0.0.2", "", {}, "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ=="], + "@sapphire/pieces/@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="], - "google-gax/google-auth-library/gcp-metadata/google-logging-utils": ["google-logging-utils@0.0.2", "", {}, "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ=="], + "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.8", "", {}, "sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q=="], } } diff --git a/config.json b/config.json deleted file mode 100644 index 7b26f79..0000000 --- a/config.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "guildId": "1429026875946172459", - "clientId": "1430219756820103370", - "devs": [], - "prefixes": [ - "p!", - "P!", - "?" - ], - "macroPrefixes": [ - "++" - ], - "serverConfig": { - "welcomeChannel": "1429027697304277173", - "botCommandsChannel": "1429028988109455454", - "modLogChannel": "1430931334213406731", - "introductionsChannel": "1450859866334695517", - "emojis": { - "welcomeEmoji": "1429031070665539664" - }, - "countingChannel": "1433142662978080909", - "suspendedChannel": "1477224341744783442", - "suspendedRoleId": "1454465284982177863", - "suggestionsChannel": "1441645690727039026", - "starboardChannel": "1457370021700309083", - "moderatorRoleId": "1441833991798788126", - "rulesChannel": "1429027865957109861", - "badgeRoles": { - "Admin": "1429032043462918268", - "Staff": "1429032163319353374", - "ServerBooster": "1443507666537287761", - "BotJam2026": "1484947494671745126", - "BotJam2026Winner": "1484947868463796376", - "GitHubContributor": "1467744562280923238", - "EarlySupporter": "1449721198647705600", - "Partner": "1451799979122229383", - "Developer": "1429032223511674882", - "VIP": "1473351731705282645", - "BugHunter": "1487746162881597460" - }, - "badgeEmojis": { - "Admin": "1487745114657919026", - "Staff": "1487745132869587035", - "ServerBooster": "1487745116134441140", - "BotJam2026": "1487745119808524379", - "BotJam2026Winner": "1487745122018791434", - "GitHubContributor": "1487745129388314727", - "EarlySupporter": "1487745127509135491", - "Partner": "1487745131267489822", - "Developer": "1487745125999444080", - "VIP": "1487745134836584549", - "BugHunter": "1487745123902161139" - }, - "starboardExclude": { - "channels": { - "rules": "1429027865957109861", - "info": "1429028199840350311", - "jobBoard": "1494350974242783353" - }, - "categories": { - "mod": "1429035248754098176", - "logs": "1484208310998663329", - "other": "1532474240480317560", - "tickets": "1431492565760348281", - "important": "1444027597364400138" - } - }, - "tickets": { - "ticketsAdminId": "1493986014270717992", - "category": "1431492565760348281", - "channel": "1442927451251544236", - "transcripts": "1492501182164373659", - "database": "1492501336296521889" - } - } -} \ No newline at end of file diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..b502183 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,9 @@ +// @ts-check +import js from "@eslint/js"; +import { defineConfig } from "eslint/config"; +import tseslint from "typescript-eslint"; + +export default defineConfig({ + files: ["**/*.{ts,tsx}"], + extends: [js.configs.recommended, tseslint.configs.recommended], +}); diff --git a/package.json b/package.json index 6b781a0..6663882 100644 --- a/package.json +++ b/package.json @@ -1,28 +1,33 @@ { "name": "pandabot", - "version": "1.0.0", - "description": "Hello, I’m Panda, the kernel bot of the DevHub Discord Server", - "main": "src/index.js", + "version": "2.0.0", + "description": "General purpose Discord bot powering the DevHub Discord community", + "main": "src/index.ts", "type": "module", "scripts": { "start": "bun .", "dev": "bun --watch .", "format": "prettier --write .", - "postinstall": "node node_modules/skia-canvas/lib/prebuild.mjs download --or-compile" + "typecheck": "tsc --noEmit", + "lint": "eslint .", + "build": "tsup" }, "keywords": [], - "author": "Caleb Ephrem", + "author": "Open DevHub", "license": "GPL-3.0-only", "dependencies": { - "captcha-canvas": "^3.4.0", + "@sapphire/framework": "^5.5.1", + "@sapphire/plugin-editable-commands": "^4.0.4", "discord.js": "^14.7.1", "dotenv": "^16.0.3", - "firebase-admin": "^13.8.0", - "mongoose": "^6.9.0", - "ms": "^2.1.3", - "pretty-ms": "^8.0.0" + "lmdb": "^3.5.6", + "mongoose": "^6.9.0" }, "devDependencies": { - "prettier": "^3.8.1" + "eslint": "^10.9.1", + "prettier": "^3.8.1", + "tsup": "^8.5.1", + "typescript": "6.x", + "typescript-eslint": "^8.69.0" } } diff --git a/pandaconf.json b/pandaconf.json new file mode 100644 index 0000000..03a66b8 --- /dev/null +++ b/pandaconf.json @@ -0,0 +1,76 @@ +{ + "modules": { + "welcome": { + "enabled": true, + "dm": true, + "channel": "1429027697304277173" + }, + + "counting": { + "enabled": true, + "channel": "1433142662978080909" + }, + + "afk": { + "enabled": true + }, + + "macros": { + "enabled": true, + "deleteOG": false + }, + + "suggestion": { + "enabled": true, + "channel": "1441645690727039026" + }, + + "tickets": { + "enabled": true, + "category": "1431492565760348281", + "mention": ["1493986014270717992"], + "mods": ["1493986014270717992"], + "text": "Need help with something or have a question for the staff team? Click the button below to open a private support ticket.\nRules before opening a ticket:\n- Do not ping staff members directly.\n- Clearly describe your issue/question in the popup\n- Impatient or spam behavior will result in a ticket close.", + "transcripts": "1492501182164373659" + }, + + "starboard": { + "enabled": true, + "channel": "1457370021700309083", + "emojis": ["⭐", "πŸ’€", "🀣", "πŸ˜‚", "❀️", "😍", "πŸ”₯", "πŸ’―"], + "reactionsRequired": 4, + "exclude": { + "channels": ["1429027865957109861"], + "categories": [ + "1429035248754098176", + "1484208310998663329", + "1532474240480317560", + "1431492565760348281", + "1444027597364400138" + ] + } + }, + + "stickyMessages": { + "enabled": true, + "messages": { + "1450859866334695517": { + "content": "Welcome to DevHub! Please introduce yourself by sharing your preferred name/nickname, favorite languages/tools/frameworks, areas of interest, hobbies outside tech, and what you hope to learn or contribute here. We’re excited you’re here!", + "react": ["πŸ‘‹", "❀️"] + } + } + }, + + "easterEggs": { + "enabled": true + } + }, + + "settings": { + "serverId": "1429026875946172459", + "prefixes": { + "commands": ["p!"], + "macros": ["++", "?"] + } + } +} diff --git a/src/commands/afk.ts b/src/commands/afk.ts new file mode 100644 index 0000000..8557f51 --- /dev/null +++ b/src/commands/afk.ts @@ -0,0 +1,76 @@ +import { Args, Command } from "@sapphire/framework"; +import type { ChatInputCommandInteraction, Message } from "discord.js"; +import { EmbedBuilder } from "discord.js"; +import { open } from "lmdb"; +import path from "path"; +import { config } from "../config/app.ts"; +import { colors } from "../constants/colors.ts"; +import { dbkeys, dbPath } from "../constants/db.ts"; +import type { AFKDB } from "../types/afk.ts"; + +const db = open(path.join(dbPath, dbkeys.afk), { + compression: true, +}); + +export class PingCommand extends Command { + public constructor(context: Command.LoaderContext) { + super(context, { + name: "afk", + description: "Notify friends when you get a mention while afk", + options: ["text"], + }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + if (config.modules.afk.enabled) { + registry.registerChatInputCommand((builder) => + builder + .setName(this.name) + .setDescription(this.description) + .addStringOption((option) => + option + .setName("text") + .setDescription("The text to show when you're mentioned"), + ), + ); + } + } + + public async messageRun(message: Message, args: Args) { + if (message.author.bot || !config.modules.afk.enabled) return; + + const entry = db.get(message.author.id); + + const reason = await args.rest("string").catch(() => null); + + db.put(message.author.id, { ...entry, reason }); + + const embed = new EmbedBuilder() + .setDescription(`Set your status to AFK${reason ? `: ${reason}` : ""}`) + .setColor(colors.success) + .setAuthor({ + name: message.author.displayName, + iconURL: message.author.displayAvatarURL(), + }); + + await message.reply({ embeds: [embed] }); + } + + public async chatInputRun(interaction: ChatInputCommandInteraction) { + const entry = db.get(interaction.user.id); + + const reason = interaction.options.getString("text"); + + db.put(interaction.user.id, { ...entry, reason }); + + const embed = new EmbedBuilder() + .setDescription(`Set your status to AFK${reason ? `: ${reason}` : ""}`) + .setColor(colors.success) + .setAuthor({ + name: interaction.user.displayName, + iconURL: interaction.user.displayAvatarURL(), + }); + + await interaction.reply({ embeds: [embed] }); + } +} diff --git a/src/commands/dm.ts b/src/commands/dm.ts new file mode 100644 index 0000000..6068c57 --- /dev/null +++ b/src/commands/dm.ts @@ -0,0 +1,41 @@ +import { Command } from "@sapphire/framework"; +import type { ChatInputCommandInteraction } from "discord.js"; + +export class DM extends Command { + public constructor(context: Command.LoaderContext) { + super(context, { + name: "dm", + description: "Send a message as the bot in someone's dms", + preconditions: ["OwnerOnly"], + }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder) => + builder + .setName(this.name) + .setDescription(this.description) + .addUserOption((option) => + option + .setName("user") + .setDescription("The user to send dm to") + .setRequired(true), + ) + .addStringOption((option) => + option + .setName("text") + .setDescription("The text to send in the user's dms") + .setRequired(true), + ), + ); + } + + public async chatInputRun(interaction: ChatInputCommandInteraction) { + const user = interaction.options.getUser("user", true); + const text = interaction.options.getString("text", true); + + await user.send(text); + + await interaction.reply({ content: "DM sent.", ephemeral: true }); + } +} diff --git a/src/commands/leaderboards/counting.js b/src/commands/leaderboards/counting.js deleted file mode 100644 index a89e2d6..0000000 --- a/src/commands/leaderboards/counting.js +++ /dev/null @@ -1,42 +0,0 @@ -import { EmbedBuilder } from "discord.js"; -import Counting from "../../models/Counting.js"; - -export default { - callback: async (client, interaction) => { - if (interaction.user.bot) return; - - // Database profile - const counts = await Counting.find().sort({ counts: -1 }).limit(15); - const leaderboard = counts.map((c, index) => ({ - userId: c.userId, - counts: c.counts, - rank: index + 1, - })); - - const embed = new EmbedBuilder() - .setTitle(`Counting Leaderboard`) - .setColor(0x2b2d31); - - if (leaderboard.length === 0) { - embed.setDescription("No counts yet!"); - } else { - embed.setDescription( - leaderboard - .map( - (entry) => - `**${entry.rank}.** <@${entry.userId}>${ - entry.userId == interaction.user.id ? " (You)" : "" - } - **${entry.counts}**`, - ) - .join("\n"), - ); - } - - await interaction.reply({ - embeds: [embed], - }); - }, - - name: "countinglb", - description: "View the counting leaderboard", -}; diff --git a/src/commands/misc/dm.js b/src/commands/misc/dm.js deleted file mode 100644 index 76e1572..0000000 --- a/src/commands/misc/dm.js +++ /dev/null @@ -1,93 +0,0 @@ -import { ApplicationCommandOptionType, PermissionFlagsBits } from "discord.js"; - -import buildModal from "../../utils/buildModal.js"; - -export default { - /** - * - * @param {Client} client - * @param {Interaction} interaction - */ - callback: async (client, interaction) => { - if (!interaction.inGuild()) - return interaction.reply({ - content: "You can only run this command inside a server.", - ephemeral: true, - }); - - if (interaction.guild.ownerId !== interaction.user.id) { - return interaction.reply({ - content: "You must be the owner of the server to use this command.", - ephemeral: true, - }); - } - - const modalId = `dm_modal_${interaction.user.id}_${Date.now()}`; - const modal = buildModal(client, { - customId: modalId, - title: "Send Message", - fields: [ - { - customId: "content", - label: "Content", - style: "PARAGRAPH", - placeholder: "Message content (max 2048)", - required: true, - maxLength: 2048, - }, - ], - }); - - try { - await interaction.showModal(modal); - } catch (err) { - console.error("Failed to show sendmsg modal:", err); - return interaction.reply({ - content: "Something went wrong showing the form. Try again.", - ephemeral: true, - }); - } - - let modalSubmit; - try { - modalSubmit = await interaction.awaitModalSubmit({ - filter: (m) => - m.user.id === interaction.user.id && m.customId === modalId, - time: 300000, - }); - } catch (err) { - console.error("dm modal submit error or timeout:", err); - return; - } - - const content = modalSubmit.fields.getTextInputValue("content"); - const user = interaction.options.getUser("target-user"); - - try { - await user.send(content); - await modalSubmit.reply({ - content: "Message sent successfully!", - ephemeral: true, - }); - } catch (err) { - console.error("Failed to send DM:", err); - try { - await modalSubmit.reply({ - content: "Failed to send message to this user.", - ephemeral: true, - }); - } catch {} - } - }, - name: "dm", - description: "Direct message a user", - options: [ - { - name: "target-user", - description: "The user to DM", - type: ApplicationCommandOptionType.User, - required: true, - }, - ], - permissionsRequired: [PermissionFlagsBits.Administrator], -}; diff --git a/src/commands/misc/edit-profile.js b/src/commands/misc/edit-profile.js deleted file mode 100644 index 7394bb2..0000000 --- a/src/commands/misc/edit-profile.js +++ /dev/null @@ -1,141 +0,0 @@ -import Profile from "../../models/Profile.js"; - -export default { - callback: async (client, interaction) => { - try { - if (interaction.user.bot) return; - - let error; - - const bio = interaction.options.getString("bio"); - const country = interaction.options.getString("country"); - const age = interaction.options.getInteger("age"); - const github = interaction.options.getString("github"); - const portfolio = interaction.options.getString("portfolio"); - const stack = interaction.options.getString("stack"); - const hobbies = interaction.options.getString("hobbies"); - - let profile = await Profile.findOne({ userId: interaction.user.id }); - - if (!profile) { - profile = new Profile({ userId: interaction.user.id }); - } - - switch (true) { - case bio !== null && (bio.length < 2 || bio.length > 200): - error = "Bio must be between 2 and 200 characters."; - break; - case country !== null && (country.length < 2 || country.length > 100): - error = "Country must be between 2 and 100 characters."; - break; - case age !== null && (age < 1 || age > 1000): - error = "Age must be a number between 1 and 1000."; - break; - case stack !== null && (stack.length < 2 || stack.length > 200): - error = "Stack must be between 2 and 200 characters."; - break; - case hobbies !== null && (hobbies.length < 2 || hobbies.length > 200): - error = "Hobbies must be between 2 and 200 characters."; - break; - case github !== null && - !/^https?:\/\/(www\.)?github\.com\/[A-Za-z0-9_-]+\/?$/.test(github): - error = "GitHub link must be a valid GitHub profile URL."; - break; - case portfolio !== null && - !/^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$/.test( - portfolio, - ): - error = "Portfolio link must be a valid URL."; - break; - } - - if (error) { - await interaction.reply({ - content: `❌ ${error}`, - ephemeral: true, - }); - return; - } - - if (bio !== null) profile.bio = bio; - if (country !== null) profile.country = country; - if (age !== null) profile.age = age; - if (github !== null) profile.github = github; - if (portfolio !== null) profile.portfolio = portfolio; - if (stack !== null) profile.stack = stack; - if (hobbies !== null) profile.hobbies = hobbies; - - await profile.save(); - - await interaction.reply({ - content: "βœ… Profile updated.", - ephemeral: true, - }); - } catch (error) { - console.error("Error editing profile:", error); - await interaction.reply({ - content: - "❌ An error occurred while updating your profile, Please make sure your inputs are valid (e.g. age should be a number between 1 and 1000).", - ephemeral: true, - }); - } - }, - - name: "edit-profile", - description: "Edit your profile", - - options: [ - { - name: "bio", - description: "Your bio", - type: 3, - required: false, - min_length: 2, - max_length: 200, - }, - { - name: "country", - description: "Your country", - type: 3, - required: false, - min_length: 2, - max_length: 100, - }, - { - name: "age", - description: "Your age", - type: 4, - required: false, - min_value: 1, - max_value: 1000, - }, - { - name: "stack", - description: "Your development stack", - type: 3, - required: false, - min_length: 2, - max_length: 200, - }, - { - name: "github", - description: "GitHub profile link", - type: 3, - required: false, - }, - { - name: "portfolio", - description: "Portfolio link", - type: 3, - required: false, - }, - { - name: "hobbies", - description: "Your hobbies", - type: 3, - required: false, - min_length: 2, - max_length: 200, - }, - ], -}; diff --git a/src/commands/misc/ping.js b/src/commands/misc/ping.js deleted file mode 100644 index 5b1faff..0000000 --- a/src/commands/misc/ping.js +++ /dev/null @@ -1,20 +0,0 @@ -export default { - name: "ping", - description: "Replies with the bot ping!", - - callback: async (client, interaction) => { - try { - await interaction.deferReply(); - - const reply = await interaction.fetchReply(); - - const ping = reply.createdTimestamp - interaction.createdTimestamp; - - interaction.editReply( - `Pong! Client ${ping}ms | Websocket: ${client.ws.ping}ms`, - ); - } catch (err) { - console.error("Ping Command Error:", err); - } - }, -}; diff --git a/src/commands/misc/profile.js b/src/commands/misc/profile.js deleted file mode 100644 index c658736..0000000 --- a/src/commands/misc/profile.js +++ /dev/null @@ -1,75 +0,0 @@ -import data from "../../../config.json" with { type: "json" }; -import Profile from "../../models/Profile.js"; -import buildProfileMessage from "../../utils/buildProfileMessage.js"; - -const { serverConfig } = data; - -export default { - callback: async (client, interaction) => { - if (interaction.user.bot) return; - - const target = interaction.options?.getUser("user") || interaction.user; - const member = await interaction.guild.members.fetch(target.id); - - const { badgeRoles, badgeEmojis } = serverConfig; - - // Badges - const badges = Object.entries(badgeRoles) - .filter(([key, roleId]) => member.roles.cache.has(roleId)) - .map(([key]) => { - const emojiId = badgeEmojis[key]; - return emojiId ? `<:${key}:${emojiId}>` : null; - }) - .filter(Boolean); - - const badgeString = badges.length ? `${badges.join(" ")}` : ""; - - // Database profile - const profile = await Profile.findOne({ userId: target.id }); - - const bio = profile?.bio; - const country = profile?.country; - const age = profile?.age; - const stack = profile?.stack; - const github = profile?.github; - const portfolio = profile?.portfolio; - const hobbies = profile?.hobbies; - - const joined = member.joinedAt - ? member.joinedAt.toLocaleDateString("en-US", { - month: "short", - year: "numeric", - }) - : "Unknown"; - - const payload = buildProfileMessage({ - target, - member, - profile: { - bio, - country, - age, - stack, - github, - portfolio, - hobbies, - }, - joined, - badgeString, - }); - - await interaction.reply(payload); - }, - - name: "profile", - description: "View a user's profile", - - options: [ - { - name: "user", - description: "User to view", - type: 6, - required: false, - }, - ], -}; diff --git a/src/commands/misc/react.js b/src/commands/misc/react.js deleted file mode 100644 index bba3f95..0000000 --- a/src/commands/misc/react.js +++ /dev/null @@ -1,90 +0,0 @@ -import { ApplicationCommandOptionType, PermissionFlagsBits } from "discord.js"; - -export default { - /** - * - * @param {Client} client - * @param {Interaction} interaction - */ - callback: async (client, interaction) => { - if (!interaction.inGuild()) { - return interaction.reply({ - content: "You can only run this command inside a server.", - ephemeral: true, - }); - } - - const message = interaction.options.getString("message"); - let targetMessage; - - try { - const url = new URL(message); - const pathParts = url.pathname.split("/").filter(Boolean); - - // format: /channels/// - if (pathParts.length < 4 || pathParts[0] !== "channels") { - throw new Error("Invalid message URL format."); - } - - const [, guildId, channelId, messageId] = pathParts; - - const channel = await client.channels.fetch(channelId); - targetMessage = await channel.messages.fetch(messageId); - } catch (err) { - console.error("Failed to fetch target message:", err); - return interaction.reply({ - content: - "Invalid message link provided. Please check the URL and try again.", - ephemeral: true, - }); - } - - if (!targetMessage) { - return interaction.reply({ - content: - "Could not find the specified message. Please check the link and try again.", - ephemeral: true, - }); - } - - try { - const reactionsString = interaction.options.getString("reactions"); - if (reactionsString) { - const reactions = reactionsString.split(",").map((r) => r.trim()); - for (const reaction of reactions) { - await targetMessage.react(reaction).catch((err) => { - console.error(`Failed to add reaction ${reaction}:`, err); - }); - } - } - - return interaction.reply({ - content: "Reactions added successfully!", - ephemeral: true, - }); - } catch (err) { - console.error("Failed to add reactions:", err); - return interaction.reply({ - content: - "Failed to add reactions to the message. Please ensure I have permission to react and try again.", - ephemeral: true, - }); - } - }, - name: "react", - description: "React to a message by link", - options: [ - { - name: "message", - description: "The message to react to (link)", - type: ApplicationCommandOptionType.String, - required: true, - }, - { - name: "reactions", - description: "The reactions to add (comma separated, e.g. πŸ‘,πŸ‘Ž)", - type: ApplicationCommandOptionType.String, - }, - ], - permissionsRequired: [PermissionFlagsBits.Administrator], -}; diff --git a/src/commands/misc/sendembed.js b/src/commands/misc/sendembed.js deleted file mode 100644 index 74c1db5..0000000 --- a/src/commands/misc/sendembed.js +++ /dev/null @@ -1,116 +0,0 @@ -import { EmbedBuilder, PermissionFlagsBits } from "discord.js"; - -import buildModal from "../../utils/buildModal.js"; - -export default { - /** - * - * @param {Client} client - * @param {Interaction} interaction - */ - callback: async (client, interaction) => { - if (!interaction.inGuild()) - return interaction.reply({ - content: "You can only run this command inside a server.", - ephemeral: true, - }); - - const modalId = `sendmsg_modal_${interaction.user.id}_${Date.now()}`; - const modal = buildModal(client, { - customId: modalId, - title: "Send Embed Message", - fields: [ - { - customId: "title", - label: "Title", - style: "SHORT", - placeholder: "Message title", - required: true, - maxLength: 256, - }, - { - customId: "description", - label: "Description", - style: "PARAGRAPH", - placeholder: "Message description (max 2048)", - required: true, - maxLength: 2048, - }, - { - customId: "footer", - label: "Footer (optional)", - style: "SHORT", - placeholder: "Optional footer text for the embed", - required: false, - maxLength: 256, - }, - ], - }); - - try { - await interaction.showModal(modal); - } catch (err) { - console.error("Failed to show sendmsg modal:", err); - return interaction.reply({ - content: "Something went wrong showing the form. Try again.", - ephemeral: true, - }); - } - - let modalSubmit; - try { - modalSubmit = await interaction.awaitModalSubmit({ - filter: (m) => m.user.id === interaction.user.id, - time: 300000, - }); - } catch (err) { - console.error("sendmsg modal submit error or timeout:", err); - return; - } - - const title = modalSubmit.fields.getTextInputValue("title"); - const description = modalSubmit.fields.getTextInputValue("description"); - let footer = null; - try { - footer = modalSubmit.fields.getTextInputValue("footer") || null; - } catch (e) { - footer = null; - } - - const targetChannel = interaction.channel; - if (!targetChannel || !targetChannel.send) { - try { - await modalSubmit.reply({ - content: "Unable to send message to this channel.", - ephemeral: true, - }); - } catch {} - return; - } - - const suggestionEmbed = new EmbedBuilder() - .setTitle(title) - .setDescription(description) - .setColor(0x5865f2); - if (footer) suggestionEmbed.setFooter({ text: footer }); - - try { - await targetChannel.send({ embeds: [suggestionEmbed] }); - await modalSubmit.reply({ - content: "Message sent successfully!", - ephemeral: true, - }); - } catch (err) { - console.error("Failed to send message to channel:", err); - try { - await modalSubmit.reply({ - content: "Failed to send message to this channel.", - ephemeral: true, - }); - } catch {} - } - }, - name: "sendembed", - description: "Send embed from panda bot", - permissionsRequired: [PermissionFlagsBits.Administrator], -}; diff --git a/src/commands/misc/sendmsg.js b/src/commands/misc/sendmsg.js deleted file mode 100644 index 7f48375..0000000 --- a/src/commands/misc/sendmsg.js +++ /dev/null @@ -1,46 +0,0 @@ -import { ApplicationCommandOptionType, PermissionFlagsBits } from "discord.js"; - -export default { - /** - * - * @param {Client} client - * @param {Interaction} interaction - */ - callback: async (client, interaction) => { - if (!interaction.inGuild()) - return interaction.reply({ - content: "You can only run this command inside a server.", - ephemeral: true, - }); - - const content = interaction.options.getString("content"); - - try { - await interaction.channel.send( - content.length > 2000 ? content.slice(0, 1997) + "..." : content, - ); - await interaction.reply({ - content: "Message sent successfully.", - ephemeral: true, - }); - } catch (err) { - console.error("Failed to send message:", err); - await interaction.reply({ - content: "Something went wrong sending the message. Try again.", - ephemeral: true, - }); - } - }, - name: "sendmsg", - description: "Send message from panda bot", - options: [ - { - name: "content", - description: "Message content to send (max 2000 characters)", - type: ApplicationCommandOptionType.String, - required: true, - maxLength: 2000, - }, - ], - permissionsRequired: [PermissionFlagsBits.Administrator], -}; diff --git a/src/commands/moderation/verifyrequest.js b/src/commands/moderation/verifyrequest.js deleted file mode 100644 index a841cac..0000000 --- a/src/commands/moderation/verifyrequest.js +++ /dev/null @@ -1,89 +0,0 @@ -import { createCaptchaSync } from "captcha-canvas"; -import { - ApplicationCommandOptionType, - AttachmentBuilder, - EmbedBuilder, - MessageFlags, - PermissionFlagsBits -} from "discord.js"; -import data from "../../../config.json" with { type: "json" }; -import SuspendedMember from "../../models/SuspendedMember.js"; -import Verification from "../../models/Verification.js"; - -const { serverConfig } = data; - -export default { - callback: async (client, interaction) => { - await interaction.deferReply({ flags: [MessageFlags.Ephemeral] }); - - const optMember = interaction.options.getMember("target-user"); - const suspendedRole = interaction.guild.roles.cache.get(serverConfig.suspendedRoleId); - - if (!optMember) return interaction.editReply("That member does not exist."); - if (!suspendedRole) return interaction.editReply("Suspended role is not configured correctly."); - if (optMember.roles.cache.has(suspendedRole.id)) return interaction.editReply("User is already under verification."); - - const { image: imageBuffer, text: captchaText } = createCaptchaSync(350, 120, { - captcha: { - characters: 6, - size: 50, - color: "#5865f2", - skew: true - }, - decoy: { opacity: 0.3, total: 20 }, - trace: { color: "#ed4245", size: 3, opacity: 0.5 } -}); - - const attachment = new AttachmentBuilder(imageBuffer, { name: "captcha.png" }); - - try { - await SuspendedMember.findOneAndUpdate( - { guildId: interaction.guild.id, userId: optMember.id }, - { guildId: interaction.guild.id, userId: optMember.id, roleId: suspendedRole.id }, - { upsert: true, new: true } - ); - - await Verification.findOneAndUpdate( - { guildId: interaction.guild.id, userId: optMember.id }, - { guildId: interaction.guild.id, userId: optMember.id, captchaAnswer: captchaText.toLowerCase() }, - { upsert: true } - ); - - - await optMember.roles.add(suspendedRole, "Manual Verification Request"); - const dmEmbed = new EmbedBuilder() - .setTitle("πŸ”’ Account Verification Required") - .setDescription(`A moderator has requested verification for your profile in **${interaction.guild.name}**.\n\nPlease type the distorted characters displayed in the image below into this chat to restore access:\n\n*(Case-insensitive. Expires in 1 hour)*`) - .setColor("#ed4245") - .setImage("attachment://captcha.png") - .setTimestamp(); - let dmSent = true; - await optMember.send({ embeds: [dmEmbed], files: [attachment] }).catch(() => { - dmSent = false; - }); - if (!dmSent) { - await interaction.editReply({ - content: `⚠️ Appended restriction role, but **could not DM** **${optMember.user.tag}** (DMs are closed!).`, -}); - return; -} - await interaction.editReply(`Done! Sent a CAPTCHA verification challenge to **${optMember.user.tag}**.`); -} catch (err) { - console.error(err); - await optMember.roles.remove(suspendedRole, "Verification setup failed").catch(() => {}); - await interaction.editReply("An internal configuration error occurred."); - } - }, - name: "verify-request", - description: "Force a user to complete an official visual image verification check.", - options: [ - { - name: "target-user", - description: "The suspicious account profile.", - type: ApplicationCommandOptionType.User, - required: true, - } - ], - permissionsRequired: [PermissionFlagsBits.MuteMembers], - botPermissions: [PermissionFlagsBits.ManageRoles], -}; diff --git a/src/commands/ping.ts b/src/commands/ping.ts new file mode 100644 index 0000000..ed8d3a4 --- /dev/null +++ b/src/commands/ping.ts @@ -0,0 +1,41 @@ +import { Command } from "@sapphire/framework"; +import { send } from "@sapphire/plugin-editable-commands"; +import type { ChatInputCommandInteraction, Message } from "discord.js"; + +export class PingCommand extends Command { + public constructor(context: Command.LoaderContext) { + super(context, { + name: "ping", + aliases: ["pong"], + description: "Ping bot to see if it is alive", + }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder) => + builder.setName(this.name).setDescription(this.description), + ); + } + + public async messageRun(message: Message) { + if (message.author.bot) return; + + const msg = await send(message, "Ping :3"); + + const content = `Pong! Bot Latency ${Math.round(this.container.client.ws.ping)}ms. API Latency ${ + msg.createdTimestamp - message.createdTimestamp + }ms.`; + + return msg.edit(content); + } + + public async chatInputRun(interaction: ChatInputCommandInteraction) { + const msg = await interaction.reply("Ping :3"); + + const content = `Pong! Bot Latency ${Math.round(this.container.client.ws.ping)}ms. API Latency ${ + msg.createdTimestamp - interaction.createdTimestamp + }ms.`; + + return msg.edit(content); + } +} diff --git a/src/commands/postrules.ts b/src/commands/postrules.ts new file mode 100644 index 0000000..f06b9d3 --- /dev/null +++ b/src/commands/postrules.ts @@ -0,0 +1,40 @@ +import { Command } from "@sapphire/framework"; +import type { Message } from "discord.js"; +import { EmbedBuilder, PermissionFlagsBits } from "discord.js"; +import { config } from "../config/app.ts"; +import { colors } from "../constants/colors.ts"; +import rules from "../data/rules.json" with { type: "json" }; + +export class PostRules extends Command { + public constructor(context: Command.LoaderContext) { + super(context, { + name: "postrules", + aliases: ["rules"], + description: "Server rules", + requiredUserPermissions: [PermissionFlagsBits.Administrator], + }); + } + + public async messageRun(message: Message) { + if (message.author.bot) return; + + const ruleList = rules + .map((rule) => + [`### ${rule.t}`, rule.pts.map((pt) => `- ${pt}`).join("\n")].join( + "\n", + ), + ) + .join("\n"); + + const embed = new EmbedBuilder() + .setTitle(`${message.guild?.name} Server Rules`) + .setDescription(ruleList) + .setColor(colors.primary) + .setThumbnail(message.guild?.iconURL() ?? null); + + if (message.channel.isSendable()) + await message.channel.send({ embeds: [embed] }); + + if (config.modules.macros.deleteOG) await message.delete(); + } +} diff --git a/src/commands/sendmsg.ts b/src/commands/sendmsg.ts new file mode 100644 index 0000000..8273b3c --- /dev/null +++ b/src/commands/sendmsg.ts @@ -0,0 +1,37 @@ +import { Command } from "@sapphire/framework"; +import { + PermissionFlagsBits, + type ChatInputCommandInteraction, +} from "discord.js"; + +export class SendMessage extends Command { + public constructor(context: Command.LoaderContext) { + super(context, { + name: "sendmsg", + description: "Send a message as the bot", + requiredUserPermissions: [PermissionFlagsBits.Administrator], + }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder) => + builder + .setName(this.name) + .setDescription(this.description) + .addStringOption((option) => + option + .setName("text") + .setDescription("The text to send in the current channel") + .setRequired(true), + ), + ); + } + + public async chatInputRun(interaction: ChatInputCommandInteraction) { + const text = interaction.options.getString("text", true); + + if (interaction.channel?.isSendable()) await interaction.channel.send(text); + + await interaction.reply({ content: "Text sent.", ephemeral: true }); + } +} diff --git a/src/commands/setcount.ts b/src/commands/setcount.ts new file mode 100644 index 0000000..c418b85 --- /dev/null +++ b/src/commands/setcount.ts @@ -0,0 +1,90 @@ +import { Args, Command } from "@sapphire/framework"; +import { + MessageFlags, + PermissionFlagsBits, + type ChatInputCommandInteraction, + type Message, +} from "discord.js"; +import { open } from "lmdb"; +import path from "path"; +import { dbkeys, dbPath } from "../constants/db.ts"; +import type { CountDB } from "../types/counting.ts"; + +const db = open(path.join(dbPath, dbkeys.counting), {}); + +export class SetCount extends Command { + public constructor(context: Command.LoaderContext) { + super(context, { + name: "setcount", + description: "Set the current count manually", + requiredUserPermissions: [PermissionFlagsBits.Administrator], + }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand((builder) => + builder + .setName(this.name) + .setDescription(this.description) + .addIntegerOption((option) => + option + .setName("count") + .setDescription("Count to set to") + .setRequired(true), + ) + .addIntegerOption((option) => + option.setName("saves").setDescription("Saves to set to"), + ), + ); + } + + async messageRun(message: Message, args: Args) { + if (message.author.bot) return; + + const data = db.get(dbkeys.counting) ?? { + lastUser: "", + lastCount: 0, + saves: 0, + }; + + const { lastUser, lastCount, saves } = data; + + const lastCountArg = await args.pick("integer").catch(() => lastCount); + const savesArg = await args.pick("integer").catch(() => saves); + + db.put(dbkeys.counting, { + lastUser, + lastCount: lastCountArg, + saves: savesArg, + }); + + await message.reply( + `Count updated to ${lastCountArg}, the next number should be ${lastCountArg + 1}`, + ); + } + + async chatInputRun(interaction: ChatInputCommandInteraction) { + const data = db.get(dbkeys.counting) ?? { + lastUser: "", + lastCount: 0, + saves: 0, + }; + + const { lastUser, lastCount, saves } = data; + + const lastCountOpt = + interaction.options.getInteger("count", true) ?? lastCount; + const savesOpt = interaction.options.getInteger("saves") ?? saves; + + db.put(dbkeys.counting, { + lastUser, + lastCount: lastCountOpt, + saves: savesOpt, + }); + + await interaction.reply({ + content: `Count updated to ${lastCountOpt}, the next number should be ${lastCountOpt + 1}`, + flags: MessageFlags.Ephemeral, + }); + } +} diff --git a/src/commands/static/partnershipinfo.js b/src/commands/static/partnershipinfo.js deleted file mode 100644 index 2fa0d43..0000000 --- a/src/commands/static/partnershipinfo.js +++ /dev/null @@ -1,56 +0,0 @@ -import { EmbedBuilder } from "discord.js"; -import data from "../../../config.json" with { type: "json" }; - -const { serverConfig } = data; - -export default { - name: "partnershipinfo", - description: "Provides information about partnership.", - /** - * - * @param {Client} client - * @param {Interaction} interaction - */ - callback: (client, interaction) => { - const ticketChannelId = serverConfig.ticketChannel; - const ticketInfo = `If you're interested in partnering with us, feel free to open a ticket and tell us a bit about your server. Partnerships are a great way for communities to support each other through cross-promotion, collaboration, and shared growth within the tech space. - -To open a partnership ticket, head over to <#${ticketChannelId}> and select the **β€œPartnership”** option from the dropdown menu. You’ll be guided through a short form where you can provide details about your server. - -**Partnership Requirements:** - -- Your server must have **at least 100 members**. -- The server should be **active**, with regular conversations and community engagement. -- Your community must be **Tech / IT related** (programming, development, cybersecurity, AI, etc). -- **SFW only** β€” servers containing NSFW or inappropriate content will not be considered. -- **Community must be enabled** on your Discord server. -- The server should have a **clear purpose or theme** that members can easily understand. -- Channels should be **well organized with a clean structure**. -- A **moderation team** should be present to maintain the server. -- **Server rules must be visible and accessible** to all members. -- The server must be **at least 2 weeks old**. -- You must provide a **permanent (non-expiring) invite link**. -- Your server must have a **partnerships channel** where our partnership message can remain visible. - -**Partnership Benefits:** - -- **Cross-promotion** between both communities through partnership channels. -- Increased **visibility and exposure** for your server within the DevHub community. -- Opportunities for **community collaborations** such as coding events, hackathons, or learning sessions. -- Ability to **share announcements or major updates** with our community when relevant. -- **Mutual support between staff teams**, including communication regarding community issues. -- Ability to submit **ban requests** to help keep both communities safe. -`; - - const embed = new EmbedBuilder() - .setTitle("πŸ“˜ Partnership Info") - .setDescription(ticketInfo.trim()) - .setColor(0x5865f2) - .setFooter({ - text: `Requested by ${interaction.user.tag}`, - iconURL: interaction.user.displayAvatarURL(), - }) - .setTimestamp(); - return interaction.reply({ embeds: [embed] }); - }, -}; diff --git a/src/commands/static/suggestinfo.js b/src/commands/static/suggestinfo.js deleted file mode 100644 index caa1af0..0000000 --- a/src/commands/static/suggestinfo.js +++ /dev/null @@ -1,47 +0,0 @@ -import { EmbedBuilder } from "discord.js"; - -export default { - name: "suggestinfo", - description: "Provides information about /suggest command.", - /** - * - * @param {Client} client - * @param {Interaction} interaction - */ - callback: (client, interaction) => { - const suggestionInfo = `Use the \`/suggest\` command anywhere in the server to share ideas or improvements with the community. -### Command Syntax -\`/suggest [image]\` -- **suggestion** *(string, required)*: The idea or feedback you want to propose. -- **image** *(attachment, optional)*: An optional image to support your suggestion (recommended if available). -### What Happens Next -- The bot will post your suggestion in the suggestions channel. -- Reaction emojis will be automatically added for voting. -### Voting Reactions -- πŸ‘ β€” **Upvote** (I support this!) -- πŸ‘Ž β€” **Downvote** (Not a fan) -- 🀷 β€” **Neutral / Unsure** -- πŸ•’ β€” **Queue** (suggestion acknowledged, pending review) -- βœ… β€” **Implemented** (set by admins/mods when suggestion is applied) -- ❌ β€” **Rejected / Not possible** -### ℹ️ Extra Info -- πŸ’¬ You can **create a thread** under any suggestion to discuss details. -- πŸ›‘οΈ Admins/mods may pin or highlight popular suggestions for visibility or keep as memory. -- πŸš€ Be clear and concise. actionable suggestions get the most traction. -- 🎨 Images, mockups, or examples make your suggestion stronger and easier to understand. -- 🀝 Respect others’ ideas. constructive discussion only. - -✨ *Your feedback shapes the community. Don’t hesitate to drop your ideas!* -`; - - const embed = new EmbedBuilder() - .setTitle("πŸ“˜ Suggestion Guide") - .setDescription(suggestionInfo.trim()) - .setColor(0x5865f2) - .setFooter({ - text: `Requested by ${interaction.user.tag} β€’ Use /suggest to send your suggestion`, - iconURL: interaction.user.displayAvatarURL(), - }); - return interaction.reply({ embeds: [embed] }); - }, -}; diff --git a/src/commands/static/ticketinfo.js b/src/commands/static/ticketinfo.js deleted file mode 100644 index ba753c0..0000000 --- a/src/commands/static/ticketinfo.js +++ /dev/null @@ -1,37 +0,0 @@ -import { EmbedBuilder } from "discord.js"; -import data from "../../../config.json" with { type: "json" }; - -const { serverConfig } = data; - -export default { - name: "ticketinfo", - description: "Provides information about tickets.", - /** - * - * @param {Client} client - * @param {Interaction} interaction - */ - callback: (client, interaction) => { - const ticketChannelId = serverConfig.ticketChannel; - const ticketInfo = `Tickets are the best way to get help and ensure moderators can respond quickly. Here’s what you can use them for: -- 🧩 General Support: For questions, technical issues, or anything else you need assistance with, tickets help us track and resolve them. -- 🎭 Request Unban / Unmute: If you or a friend need to appeal a ban, mute or suspend, open a ticket and provide the details. -- 🚨 Report User: If you need to report someone, tickets make sure the moderators see it right away and can investigate properly. -- βš’οΈ Apply For Staff: Interested in joining our moderation team? Use a ticket to submit your application and tell us why you’d be a great fit. -- 🀝 Partnership: If you're interested in partnering with us, open a ticket and provide details about your proposal. -- πŸ“ Other: For any other reasons, open a ticket and explain your situation. - -To open a ticket, go to <#${ticketChannelId}> and use the dropdown menu to select your ticket type. You’ll be guided through a simple form to explain your reason. I will handle the process, create a private channel for your case, and keep everything neat and secure. Thanks for helping us keep the community clean ✨`; - - const embed = new EmbedBuilder() - .setTitle("πŸ“˜ Ticket Guide") - .setDescription(ticketInfo.trim()) - .setColor(0x5865f2) - .setFooter({ - text: `Requested by ${interaction.user.tag}`, - iconURL: interaction.user.displayAvatarURL(), - }) - .setTimestamp(); - return interaction.reply({ embeds: [embed] }); - }, -}; diff --git a/src/commands/suggest.ts b/src/commands/suggest.ts new file mode 100644 index 0000000..416f66d --- /dev/null +++ b/src/commands/suggest.ts @@ -0,0 +1,95 @@ +import { Command } from "@sapphire/framework"; +import type { ChatInputCommandInteraction } from "discord.js"; +import { EmbedBuilder, MessageFlags } from "discord.js"; +import { config } from "../config/app.ts"; +import { colors } from "../constants/colors.ts"; + +export class Suggest extends Command { + public constructor(context: Command.LoaderContext) { + super(context, { + name: "suggest", + description: "Submit a suggestion", + }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + if (config.modules.suggestion.enabled) { + registry.registerChatInputCommand((builder) => + builder + .setName(this.name) + .setDescription(this.description) + .addStringOption((option) => + option + .setName("suggestion") + .setDescription("The suggestion you want to make") + .setRequired(true), + ) + .addAttachmentOption((option) => + option + .setName("attachment") + .setDescription("Image attachment for the suggestion"), + ), + ); + } + } + + public async chatInputRun(interaction: ChatInputCommandInteraction) { + const text = interaction.options.getString("suggestion", true); + const attachment = interaction.options.getAttachment("attachment"); + + const suggestionChannel = await interaction.guild?.channels.fetch( + config.modules.suggestion.channel, + ); + + if (!suggestionChannel || !suggestionChannel.isTextBased()) + return await interaction.reply({ + content: "Suggestion system not configured yet.", + flags: MessageFlags.Ephemeral, + }); + + // only 4/10 consecutive suggestions can be from the same user + const spam = + (await suggestionChannel.messages.fetch({ limit: 10 })).filter( + (msg) => msg.embeds[0]?.footer?.text === interaction.user.id, + ).size > 4; + + if (spam) + return await interaction.reply({ + content: + "You already have sent enough suggestions for this round. Try again later.", + flags: MessageFlags.Ephemeral, + }); + + const embed = new EmbedBuilder() + .setAuthor({ + name: `New suggestion by ${interaction.user.globalName}`, + iconURL: interaction.user.displayAvatarURL(), + }) + .setDescription(text) + .setColor(colors.primary) + .setFooter({ text: interaction.user.id }) + .setTimestamp(); + + if (attachment?.contentType?.startsWith("image/")) + embed.setImage(attachment.url); + + if (suggestionChannel.isSendable()) { + const suggestion = await suggestionChannel.send({ embeds: [embed] }); + + await interaction.reply({ + content: "Suggestion submitted successfully.", + flags: MessageFlags.Ephemeral, + }); + + await suggestion.react("πŸ‘"); + await suggestion.react("πŸ‘Ž"); + await suggestion.react("🀷"); + } else { + await interaction.reply({ + content: + "Couldn't send suggestions at this time. Please try again later.", + flags: MessageFlags.Ephemeral, + }); + } + } +} diff --git a/src/commands/suggestion/suggest.js b/src/commands/suggestion/suggest.js deleted file mode 100644 index 1d6dc56..0000000 --- a/src/commands/suggestion/suggest.js +++ /dev/null @@ -1,85 +0,0 @@ -import { ApplicationCommandOptionType, EmbedBuilder } from "discord.js"; -import data from "../../../config.json" with { type: "json" }; - -const { serverConfig } = data; - -export default { - /** - * - * @param {Client} client - * @param {Interaction} interaction - */ - callback: async (client, interaction) => { - if (!interaction.inGuild()) { - return interaction.reply({ - content: "You can only run this command inside a server.", - ephemeral: true, - }); - } - - const suggestion = interaction.options.getString("suggestion"); - const image = interaction.options.getAttachment("image"); - - const suggestionsChannel = interaction.guild.channels.cache.get( - serverConfig.suggestionsChannel, - ); - if (!suggestionsChannel) { - return interaction.reply({ - content: "Suggestions channel is not configured yet.", - ephemeral: true, - }); - } - - const suggestionEmbed = new EmbedBuilder() - .setAuthor({ - name: `New Suggestion β€’ ${interaction.user.tag}`, - iconURL: interaction.user.displayAvatarURL({ dynamic: true }), - }) - .setDescription(suggestion) - .setColor(0x11ee11) - .setFooter({ - text: `Use /suggest to send your own suggestion`, - }) - .setTimestamp(); - - if (image && image.url) { - suggestionEmbed.setImage(image.url); - } - - const sent = await suggestionsChannel.send({ embeds: [suggestionEmbed] }); - - try { - await sent.react("πŸ‘"); - await sent.react("πŸ‘Ž"); - await sent.react("🀷"); - } catch (e) { - // ignore - } - - const thread = await sent.startThread({ - name: `Suggestion Discussion`, - autoArchiveDuration: 1440, - }); - - return interaction.reply({ - content: `Your suggestion has been submitted. Thank you! A discussion thread has been created: ${thread.url}`, - ephemeral: true, - }); - }, - name: "suggest", - description: "Make a suggestion for the server!", - options: [ - { - name: "suggestion", - description: "The suggestion you want to make", - type: ApplicationCommandOptionType.String, - required: true, - }, - { - name: "image", - description: "Optional image attachment for the suggestion", - type: ApplicationCommandOptionType.Attachment, - required: false, - }, - ], -}; diff --git a/src/commands/suggestion/suggestion-implemented.js b/src/commands/suggestion/suggestion-implemented.js deleted file mode 100644 index b6dfaef..0000000 --- a/src/commands/suggestion/suggestion-implemented.js +++ /dev/null @@ -1,84 +0,0 @@ -import { ApplicationCommandOptionType, EmbedBuilder, MessageFlags, PermissionFlagsBits } from "discord.js"; -import data from "../../../config.json" with { type: "json" }; - -const { serverConfig } = data; - -export default { - callback: async (client, interaction) => { - await interaction.deferReply({ flags: MessageFlags.Ephemeral }); - - if (!interaction.inGuild()) { - return interaction.editReply({ - content: "You can only run this command inside a server.", - }); - } - - const messageId = interaction.options.getString("message_id"); - const note = interaction.options.getString("note") || "This feature is now live!"; - - const suggestionsChannel = interaction.guild.channels.cache.get( - serverConfig.suggestionsChannel, - ); - if (!suggestionsChannel) { - return interaction.editReply({ - content: "Suggestions channel is not configured correctly in config.json.", - }); - } - - try { - const targetMessage = await suggestionsChannel.messages.fetch(messageId); - const originalEmbed = targetMessage.embeds[0]; - - if (!originalEmbed) { - return interaction.editReply({ - content: "Could not find an embed in that suggestion message.", - }); - } - - const updatedEmbed = EmbedBuilder.from(originalEmbed) - .setTitle("βœ… Suggestion Implemented") - .setColor(0x5865f2) - .addFields([ - { name: "Staff Note", value: note }, - { name: "Implemented By", value: `<@${interaction.user.id}>`, inline: true }, - ]); - await targetMessage.edit({ embeds: [updatedEmbed] }); - - if (targetMessage.thread) { - try { - await targetMessage.thread.send({ - content: `βœ… **Status Update:** This suggestion has been **Implemented**!\n> **Note:** ${note}`, - }); - await targetMessage.thread.setLocked(true, "Suggestion Implemented"); - } catch (threadError) { - console.error("Failed to update thread:", threadError); - } - } - return interaction.editReply({ - content: `Successfully marked suggestion as implemented: ${targetMessage.url}`, - }); - } catch (error) { - return interaction.editReply({ - content: "Failed to fetch the suggestion message. Ensure the Message ID is correct.", - }); - } - }, - - name: "suggestion-implemented", - description: "Mark a suggestion as implemented.", - permissionsRequired: [PermissionFlagsBits.ManageMessages], - options: [ - { - name: "message_id", - description: "The Message ID of the suggestion implemented", - type: ApplicationCommandOptionType.String, - required: true, - }, - { - name: "note", - description: "Optional release note or changelog link", - type: ApplicationCommandOptionType.String, - required: false, - }, - ], -}; diff --git a/src/commands/suggestion/suggestion-queue.js b/src/commands/suggestion/suggestion-queue.js deleted file mode 100644 index d9de31c..0000000 --- a/src/commands/suggestion/suggestion-queue.js +++ /dev/null @@ -1,84 +0,0 @@ -import { ApplicationCommandOptionType, EmbedBuilder, MessageFlags, PermissionFlagsBits } from "discord.js"; -import data from "../../../config.json" with { type: "json" }; - -const { serverConfig } = data; - -export default { - callback: async (client, interaction) => { - await interaction.deferReply({ flags: MessageFlags.Ephemeral }); - - if (!interaction.inGuild()) { - return interaction.editReply({ - content: "You can only run this command inside a server.", - }); - } - - const messageId = interaction.options.getString("message_id"); - const reason = interaction.options.getString("reason") || "No additional note provided."; - - const suggestionsChannel = interaction.guild.channels.cache.get( - serverConfig.suggestionsChannel, - ); - if (!suggestionsChannel) { - return interaction.editReply({ - content: "Suggestions channel is not configured correctly in config.json.", - }); - } - - try { - const targetMessage = await suggestionsChannel.messages.fetch(messageId); - const originalEmbed = targetMessage.embeds[0]; - - if (!originalEmbed) { - return interaction.editReply({ - content: "Could not find an embed in that suggestion message.", - }); - } - - const updatedEmbed = EmbedBuilder.from(originalEmbed) - .setTitle("πŸ“Œ Suggestion Queued") - .setColor(0x5865f2) - .setFields([ - { name: "Staff Note", value: reason }, - { name: "Queued By", value: `<@${interaction.user.id}>`, inline: true }, - ]); - - await targetMessage.edit({ embeds: [updatedEmbed] }); - - if (targetMessage.thread) { - try { - await targetMessage.thread.send({ - content: `πŸ“Œ **Status Update:** This suggestion has been **Queued**.\n> **Note:** ${reason}`, - }); - } catch (threadError) { - console.error("Failed to update thread:", threadError); - } - } - return interaction.editReply({ - content: `Successfully queued suggestion: ${targetMessage.url}`, - }); - } catch (error) { - return interaction.editReply({ - content: "Failed to fetch the suggestion message. Ensure the Message ID is correct.", - }); - } - }, - - name: "suggestion-queue", - description: "Queue a suggestion for future development.", - permissionsRequired: [PermissionFlagsBits.ManageMessages], - options: [ - { - name: "message_id", - description: "The Message ID of the suggestion to queue", - type: ApplicationCommandOptionType.String, - required: true, - }, - { - name: "reason", - description: "Optional roadmap detail or staff note", - type: ApplicationCommandOptionType.String, - required: false, - }, - ], -}; diff --git a/src/commands/ticket/ticket.js b/src/commands/ticket/ticket.js deleted file mode 100644 index 3a75674..0000000 --- a/src/commands/ticket/ticket.js +++ /dev/null @@ -1,161 +0,0 @@ -import { - ActionRowBuilder, - EmbedBuilder, - PermissionFlagsBits, - StringSelectMenuBuilder, - StringSelectMenuOptionBuilder, -} from "discord.js"; - -export default { - /** - * - * @param {Client} client - * @param {Interaction} interaction - */ - callback: async (client, interaction) => { - if (interaction.user.bot) return; - - const embedContent = `This channel is here to explain how our ticket system works and keep everything organized. - -Tickets are the best way to get help and ensure moderators can respond quickly. Here’s what you can use them for: -- 🧩 General Support: For questions, technical issues, or anything else you need assistance with, tickets help us track and resolve them. -- 🎭 Request Unban / Unmute: If you or a friend need to appeal a ban, mute or suspend, open a ticket and provide the details. -- 🚨 Report User: If you need to report someone, tickets make sure the moderators see it right away and can investigate properly. -- βš’οΈ Apply For Staff: Interested in joining our moderation team? Use a ticket to submit your application and tell us why you’d be a great fit. -- 🀝 Partnership: If you're interested in partnering with us, open a ticket and provide details about your proposal. -- πŸ“ Other: For any other reasons, open a ticket and explain your situation. - -You’ll be guided through a simple form to explain your reason. I will handle the process, create a private channel for your case, and keep everything neat and secure. Thanks for helping us keep the community clean ✨`; - - const selectMenu = [ - { - label: "🧩 General Support", - value: "support", - fields: [ - { - customId: "reason", - label: "What do you need help with?", - style: "PARAGRAPH", - placeholder: "Explain what you need help with", - required: true, - maxLength: 1024, - }, - ], - }, - { - label: "🎭 Request Unban / Unmute", - value: "appeal", - fields: [ - { - customId: "reason", - label: "Reason", - style: "PARAGRAPH", - placeholder: "Explain why you are requesting unban/unmute", - required: true, - maxLength: 1024, - }, - ], - }, - { - label: "🚨 Report User", - value: "report", - fields: [ - { - customId: "reason", - label: "Who are you reporting and why?", - style: "PARAGRAPH", - placeholder: "Provide details about the user you are reporting", - required: true, - maxLength: 1024, - }, - ], - }, - { - label: "βš’οΈ Apply For Staff", - value: "staff", - fields: [ - { - customId: "reason", - label: "Why do you want to join the staff team?", - style: "PARAGRAPH", - placeholder: "Explain why you want to join the staff team", - required: true, - maxLength: 1024, - }, - { - customId: "experience", - label: "Do you have any prior moderation experience?", - style: "PARAGRAPH", - placeholder: "Describe any prior moderation experience you have", - required: false, - maxLength: 1024, - }, - ], - }, - { - label: "πŸ“ Other", - value: "other", - fields: [ - { - customId: "reason", - label: "Reason", - style: "PARAGRAPH", - placeholder: "Explain why you are opening this ticket", - required: true, - maxLength: 1024, - }, - ], - }, - { - label: "🀝 Partnership", - value: "partnership", - fields: [ - { - customId: "about", - label: "What is your server about?", - style: "PARAGRAPH", - placeholder: "Provide details about your community", - required: true, - maxLength: 1024, - }, - ], - }, - ]; - - const select = new StringSelectMenuBuilder() - .setCustomId("ticket_type_select") - .setPlaceholder("Select ticket type") - .addOptions( - selectMenu.map( - (option) => - new StringSelectMenuOptionBuilder({ - label: option.label, - value: option.value, - }), - ), - ); - - const row = new ActionRowBuilder().addComponents(select); - - const embed = new EmbedBuilder() - .setTitle("🎫 Tickets") - .setDescription(embedContent); - - await interaction.deferReply({ ephemeral: true }); - - const message = await interaction.channel.send({ - embeds: [embed], - components: [row], - }); - - await interaction.editReply({ - content: "Ticketing system has been set up in this channel.", - }); - - return; - }, - - name: "ticket", - description: "Send the ticketing system setup message", - permissionsRequired: [PermissionFlagsBits.Administrator], -}; diff --git a/src/commands/tickets.ts b/src/commands/tickets.ts new file mode 100644 index 0000000..3359508 --- /dev/null +++ b/src/commands/tickets.ts @@ -0,0 +1,67 @@ +import { Command } from "@sapphire/framework"; +import type { ChatInputCommandInteraction, Message } from "discord.js"; +import { + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + EmbedBuilder, + PermissionFlagsBits, +} from "discord.js"; +import { config } from "../config/app.ts"; +import { colors } from "../constants/colors.ts"; +import { interactionKeys } from "../constants/interactions.ts"; + +export class Tickets extends Command { + public constructor(context: Command.LoaderContext) { + super(context, { + name: "tickets", + aliases: ["ticket"], + description: "Post ticket embed", + requiredUserPermissions: [PermissionFlagsBits.Administrator], + }); + } + + public override registerApplicationCommands(registry: Command.Registry) { + if (config.modules.tickets.enabled) { + registry.registerChatInputCommand((builder) => + builder.setName(this.name).setDescription(this.description), + ); + } + } + + public async messageRun(message: Message) { + if (message.author.bot) return; + + const embed = new EmbedBuilder() + .setTitle("Tickets") + .setDescription(config.modules.tickets.text) + .setColor(colors.primary); + + const row = new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setCustomId(interactionKeys.ticketButton) + .setLabel("Create a ticket") + .setStyle(ButtonStyle.Primary), + ); + + if (message.channel.isSendable()) + await message.channel.send({ embeds: [embed], components: [row] }); + } + + public async chatInputRun(interaction: ChatInputCommandInteraction) { + const embed = new EmbedBuilder() + .setTitle("Tickets") + .setDescription(config.modules.tickets.text) + .setColor(colors.primary); + + const row = new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setCustomId(interactionKeys.ticketButton) + .setLabel("Create a ticket") + .setStyle(ButtonStyle.Primary), + ); + + if (interaction.channel?.isSendable()) + await interaction.channel.send({ embeds: [embed], components: [row] }); + } +} diff --git a/src/config/app.ts b/src/config/app.ts new file mode 100644 index 0000000..3f4d4c8 --- /dev/null +++ b/src/config/app.ts @@ -0,0 +1 @@ +export { default as config } from "../../pandaconf.json" with { type: "json" }; diff --git a/src/config/env.ts b/src/config/env.ts new file mode 100644 index 0000000..28f4f30 --- /dev/null +++ b/src/config/env.ts @@ -0,0 +1,5 @@ +import "dotenv/config"; + +export const env = { + BOT_TOKEN: process.env.BOT_TOKEN, +}; diff --git a/src/constants/colors.ts b/src/constants/colors.ts new file mode 100644 index 0000000..5974aa2 --- /dev/null +++ b/src/constants/colors.ts @@ -0,0 +1,6 @@ +export const colors = { + primary: 0x5865f2, + secondary: 0x4f545c, + success: 0x23a55a, + danger: 0xf23f43, +}; diff --git a/src/constants/db.ts b/src/constants/db.ts new file mode 100644 index 0000000..d9eeda6 --- /dev/null +++ b/src/constants/db.ts @@ -0,0 +1,9 @@ +import path from "path"; + +export const dbDir = "db"; +export const dbPath = path.join(process.cwd(), dbDir); + +export const dbkeys = { + counting: "counting", + afk: "afk", +}; diff --git a/src/constants/interactions.ts b/src/constants/interactions.ts new file mode 100644 index 0000000..ac25df7 --- /dev/null +++ b/src/constants/interactions.ts @@ -0,0 +1,6 @@ +export const interactionKeys = { + ticketButton: "ticket-button", + ticketOpen: "ticket-open", + ticketReason: "ticket-reason", + ticketClose: "ticket-close", +}; diff --git a/src/contextMenus/message/report.js b/src/contextMenus/message/report.js deleted file mode 100644 index ea2c25f..0000000 --- a/src/contextMenus/message/report.js +++ /dev/null @@ -1,92 +0,0 @@ -import { - ActionRowBuilder, - ApplicationCommandType, - ButtonBuilder, - ButtonStyle, - EmbedBuilder, -} from "discord.js"; -import data from "../../../config.json" with { type: "json" }; - -const { serverConfig } = data; - -export default { - name: "Report Message", - type: ApplicationCommandType.Message, - - callback: async (client, interaction) => { - try { - const message = interaction.targetMessage; - if (!message.guild) return; - if (message.author?.bot) { - return interaction.reply({ - content: "You cannot report a bot message.", - ephemeral: true, - }); - } - const { modLogChannel } = serverConfig; - const channel = message.guild.channels.cache.get(modLogChannel); - if (!channel || !modLogChannel) { - return interaction.reply({ - content: "Reporting is not configured yet.", - ephemeral: true, - }); - } - const existing = await channel.messages.fetch({ limit: 15 }); - if ( - existing.find((m) => m.embeds[0]?.footer?.text.includes(message.id)) - ) { - return interaction.reply({ - content: "This message has already been reported recently.", - ephemeral: true, - }); - } - const embed = new EmbedBuilder() - .setTitle("Message Report") - .setColor(0xff0000) - .setAuthor({ - name: message.author.tag, - iconURL: message.author.displayAvatarURL({ dynamic: true }), - }) - .addFields( - { name: "User", value: `${message.author}`, inline: true }, - { - name: "Reporter", - value: `${interaction.user || "Unknown"}`, - inline: true, - }, - { name: "Channel", value: `<#${message.channel.id}>`, inline: true }, - { - name: "Message", - value: message.content - ? `||${message.content}||` - : `No text message`, - inline: false, - }, - ) - .setThumbnail(message.author.displayAvatarURL({ size: 1024 })) - .setFooter({ text: `Report ID: ${message.id}` }) - .setTimestamp(); - const row = new ActionRowBuilder().addComponents( - new ButtonBuilder() - .setLabel("Jump to Message") - .setStyle(ButtonStyle.Link) - .setURL(message.url), - ); - await channel.send({ - content: `<@&${serverConfig.moderatorRoleId}>`, - embeds: [embed], - components: [row], - }); - return interaction.reply({ - content: "Message reported to moderators successfully.", - ephemeral: true, - }); - } catch (err) { - console.log("Error in Report Message context menu:", err); - return interaction.reply({ - content: "An error occurred while processing your report.", - ephemeral: true, - }); - } - }, -}; diff --git a/src/contextMenus/user/userinfo.js b/src/contextMenus/user/userinfo.js deleted file mode 100644 index 031bbec..0000000 --- a/src/contextMenus/user/userinfo.js +++ /dev/null @@ -1,17 +0,0 @@ -import { ApplicationCommandType } from "discord.js"; - -export default { - name: "User Info", - type: ApplicationCommandType.User, - - callback: async (client, interaction) => { - const targetUser = interaction.targetUser; - - await interaction.reply({ - content: `User: ${targetUser.username}\nID: ${targetUser.id}\nJoined: ${ - interaction.targetMember?.joinedAt?.toDateString() || "N/A" - }`, - ephemeral: true, - }); - }, -}; diff --git a/src/data/macros.json b/src/data/macros.json index 059818f..5893260 100644 --- a/src/data/macros.json +++ b/src/data/macros.json @@ -1,263 +1,264 @@ -{ - "question": [ - { - "c": "askbetter", - "a": ["howtoask", "how2ask"], - "r": "**Ask Better Questions:** Include clear details about your problem: what you're trying to do, what you expected, what actually happened, and any relevant code or errors. This makes it much easier for others to help you.\nhttps://stackoverflow.com/help/how-to-ask" - }, - { - "c": "dontasktoask", - "a": ["ask", "justask"], - "r": "**Don't Ask to Ask:** Instead of asking if you can ask a question, just ask it directly. This helps others understand your issue right away.\nhttps://dontasktoask.com/" - }, - { - "c": "imageofanerror", - "a": ["imageoferror"], - "r": "**Avoid Images of Errors:** Please copy and paste the error message as text using code blocks. This makes it easier to read, search, and debug.\nhttps://idownvotedbecau.se/imageofatextualerror/" - }, - { - "c": "imageofcode", - "a": ["pictureofcode", "imgofcode"], - "r": "**Avoid Images of Code:** Share code as text in code blocks so others can read, copy, and test it. Images make this difficult.\nhttps://idownvotedbecau.se/imageofcode/" - }, - { - "c": "itsnotworking", - "a": ["itdoesntwork", "notworking", "doesntwork"], - "r": "**\"It's Not Working\" Isn't Enough:** Explain what you expected, what actually happened, and include relevant code or errors. More detail leads to better help.\nhttp://idownvotedbecau.se/itsnotworking/" - }, - { - "c": "mcve", - "r": "**Provide a Minimal Reproducible Example:** Share the smallest amount of code needed to reproduce your issue so others can quickly understand and test it.\nhttps://stackoverflow.com/help/minimal-reproducible-example" - }, - { - "c": "noattempt", - "r": "**Show Your Attempt:** Include what you've already tried. This helps others understand where you're stuck and avoids repeating suggestions.\nhttp://idownvotedbecau.se/noattempt/" - }, - { - "c": "nocode", - "a": ["showcode", "postcode"], - "r": "**No Code Provided:** It's difficult to help without seeing the relevant code. Please include the parts related to your issue.\nhttp://idownvotedbecau.se/nocode/" - }, - { - "c": "nodebug", - "a": ["nodebugging"], - "r": "**Try Debugging First:** Read error messages, add logs, and test parts of your code to narrow down the issue. Sharing your debugging steps helps others assist you.\nhttp://idownvotedbecau.se/nodebugging/" - }, - { - "c": "noerror", - "r": "**Include the Error Message:** If your code produces an error, share the full message. It often contains important clues.\nhttp://idownvotedbecau.se/noerror/" - }, - { - "c": "nohello", - "r": "**Don't Just Say Hello:** Ask your question directly instead of starting with only a greeting. This helps others respond more efficiently.\nhttps://www.nohello.net/" - }, - { - "c": "noresearch", - "a": ["research"], - "r": "**Do Some Research First:** Try searching or checking documentation before asking. If you still need help, mention what you've already looked at.\nhttp://idownvotedbecau.se/noresearch/" - }, - { - "c": "sask", - "r": "**Ask Directly:** Briefly describe your actual problem instead of asking if someone knows about a topic. This makes it easier to help right away." - }, - { - "c": "tldr", - "r": "**Keep It Concise:** Your message is quite long. Try summarizing the key points so others can understand your issue quickly." - }, - { - "c": "toomuchcode", - "r": "**Too Much Code:** Avoid sharing entire projects. Focus on the smallest portion of code that reproduces the issue.\nhttp://idownvotedbecau.se/toomuchcode/" - }, - { - "c": "toomuchinfo", - "r": "**Too Much Information:** Remove unrelated details and focus on what is directly relevant to your problem." - }, - { - "c": "tos", - "a": ["terms", "termsofservice", "discordtos", "guidelines", "guideline"], - "r": "**Community Guidelines:** https://discord.com/guidelines\n**Terms of Service:** https://discord.com/terms" - }, - { - "c": "tryit", - "a": ["tias"], - "r": "**Try It Yourself:** Experiment with your code or idea first. Testing things on your own is often the fastest way to learn and understand the issue." - }, - { - "c": "unclearquestion", - "a": ["unclear"], - "r": "**Unclear Question:** Please clarify what you're trying to do, include relevant code, and explain the issue more clearly.\nhttp://idownvotedbecau.se/unclearquestion/" - }, - { - "c": "xyproblem", - "a": ["xy"], - "r": "**The XY Problem:** You're asking about a specific solution instead of the actual problem. Explain your original goal so better solutions can be suggested.\nhttps://xyproblem.info/" - } - ], - "rules": [ - { - "c": "backseat", - "r": "**No Backseat Coding:** Avoid giving unsolicited advice or taking over someone else's troubleshooting unless they ask for it. It can confuse the person being helped and disrupt the flow of the conversation. Let the person helping guide the process." - }, - { - "c": "changesubjects", - "a": ["changesubject", "changetopic"], - "r": "**One Topic at a Time:** Avoid switching topics while someone is helping you with an issue. This makes it difficult to follow progress and can slow things down. Once your issue is resolved, you can start a new discussion." - }, - { - "c": "chatgpt", - "a": ["cursor", "claude", "copilot"], - "r": "**AI Usage:** AI tools can be helpful, but they may produce outdated or incorrect code. If you are sharing AI-generated code, please mention it and make sure you understand what it does. This helps others assist you more effectively." - }, - { - "c": "cheat", - "a": ["cheating"], - "r": "**No Cheating:** Do not ask for help with graded assignments, interviews, or anything involving academic or professional dishonesty. This community is here to help you learn, not to bypass the process. Focus on understanding the problem yourself." - }, - { - "c": "crypto", - "a": ["nft", "blockchain", "web3"], - "r": "**Crypto Policy:** This server does not provide support for cryptocurrency, NFTs, or blockchain-related projects. These topics are outside the scope of this community. Please use dedicated communities for that kind of help." - }, - { - "c": "dm", - "a": ["nodm", "nofriendreq", "nofriendrequest"], - "r": "**No Direct Messages for Help:** Keep help-related discussions in public channels. This allows others to learn from the conversation and lets multiple people assist if needed. It also keeps interactions transparent." - }, - { - "c": "english", - "r": "**English Only:** Please use English in this channel so moderators and members can understand and assist you. This ensures clear communication and avoids confusion. It also helps more people participate in the discussion." - }, - { - "c": "exams", - "a": ["noexams", "noactiveexams"], - "r": "**No Help with Active Exams:** Requests related to ongoing exams, certifications, or timed tests are not allowed. This includes anything that could be considered cheating. We encourage learning, not shortcuts." - }, - { - "c": "flame", - "a": ["toxic", "toxicity"], - "r": "**No Flaming or Toxicity:** Be respectful when interacting with others. Personal attacks, insults, or aggressive behavior are not allowed. Keep discussions constructive, even when you disagree." - }, - { - "c": "freework", - "a": ["labor"], - "r": "**No Requests for Free Work:** Do not ask others to build projects or features for you. This is a place to learn, not outsource work. Show what you have tried and ask for guidance instead." - }, - { - "c": "hacks", - "a": ["hacking", "cracking"], - "r": "**No Hacking or Exploits:** Do not discuss or request help with unauthorized access, exploits, or malicious activities. This includes bypassing security or abusing systems. Such topics are not allowed here." - }, - { - "c": "image", - "a": ["images"], - "r": "**Use Images Appropriately:** Avoid excessive or unnecessary images that disrupt the conversation. For code or errors, always use text and code blocks instead of screenshots. This makes it easier for others to read and help." - }, - { - "c": "moveon", - "a": ["cc"], - "r": "**Move On:** This discussion is no longer productive. Continuing it will not lead to a useful outcome. Please stop here and move to another topic." - }, - { - "c": "nickpolicy", - "a": ["nicknamepolicy", "nicknames"], - "r": "**Nickname Policy:** Use a readable and appropriate nickname. Avoid names that are hard to mention, misleading, or disruptive. Clear names make communication easier for everyone." - }, - { - "c": "noping", - "a": ["ping", "nopings"], - "r": "**No Unnecessary Pings:** Do not ping users or staff for general help. It can be disruptive and is usually unnecessary. Ask your question normally and wait for someone to respond." - }, - { - "c": "scraping", - "a": ["webscraping", "scrape", "automation"], - "r": "**Scraping Policy:** Make sure your automation follows the target site's rules and terms. Do not ask for help bypassing protections or scraping restricted platforms like Discord. Always keep your usage ethical and compliant." - }, - { - "c": "selfbot", - "a": ["selfbots"], - "r": "**No Self-Bots:** Automating a user account violates Discord's Terms of Service. This can lead to account termination. Discussion or support for self-bots is not allowed." - }, - { - "c": "spoon", - "a": ["spoonfeed", "spoonfeeding"], - "r": "**No Spoon-Feeding:** Focus on understanding the solution instead of copying it. We are here to guide you, not provide complete answers without effort. Learning the process is more valuable long-term." - }, - { - "c": "voice", - "a": ["vc"], - "r": "**Voice Channel Rules:** Keep your microphone clear and avoid background noise. Be respectful to others speaking and do not interrupt conversations. Maintain a comfortable environment for everyone." - }, - { - "c": "respecttime", - "a": ["patience", "wait"], - "r": "**Be Patient:** People here are volunteering their time to help. Avoid repeating your question or expecting instant replies. Someone will respond when they are available." - }, - { - "c": "nopressure", - "a": ["norush"], - "r": "**No Pressure:** Do not pressure others for quick answers. Marking things as urgent does not make them a priority here. Give people time to respond properly." - }, - { - "c": "formatcode", - "a": ["codeblock", "format"], - "r": "**Format Your Code:** Use proper code blocks with formatting and syntax highlighting when sharing code. This improves readability and reduces confusion. Well-formatted code is much easier to debug." - }, - { - "c": "correctchannel", - "a": ["wrongchannel", "channel"], - "r": "**Use the Correct Channel:** Post your question in the appropriate channel. This keeps discussions organized and ensures the right people see your message. It also improves your chances of getting help." - }, - { - "c": "duplicates", - "a": ["repeat", "repost"], - "r": "**No Duplicate Questions:** Do not repost the same question multiple times. This clutters the chat and makes it harder to help. If needed, update your original message instead." - }, - { - "c": "credits", - "a": ["credit", "attribution"], - "r": "**Give Credit:** If you use code or ideas from others, give proper credit. This shows respect and maintains trust within the community. It also helps others find the original source." - }, - { - "c": "nospam", - "a": ["spam"], - "r": "**No Spam:** Do not send repeated, irrelevant, or disruptive messages. This includes flooding channels or posting unnecessary content. Keep conversations meaningful." - }, - { - "c": "ads", - "a": ["advertising", "promo"], - "r": "**No Advertising:** Do not promote products, services, or servers without permission. Unsolicited promotion is not allowed. Keep the focus on discussion and help." - }, - { - "c": "safecontent", - "a": ["nsfw", "inappropriate"], - "r": "**Keep Content Appropriate:** Do not share explicit, unsafe, or inappropriate content. This includes anything that makes the space uncomfortable for others. Keep it suitable for everyone." - }, - { - "c": "privacy", - "a": ["dox", "doxxing"], - "r": "**Respect Privacy:** Do not share personal or sensitive information about yourself or others without permission. This includes private data or identifiable details. Respect boundaries at all times." - }, - { - "c": "piracy", - "a": ["warez", "cracked"], - "r": "**No Piracy:** Do not request or share pirated software, keys, or illegal downloads. This includes anything that bypasses licensing. Keep all activity legal." - }, - { - "c": "feedback", - "a": ["criticism"], - "r": "**Give Constructive Feedback:** When helping others, focus on being clear and respectful. Avoid dismissive or harsh responses. Helpful feedback should guide, not discourage." - }, - { - "c": "acknowledge", - "a": ["thanks", "resolved"], - "r": "**Acknowledge Help:** If your issue is resolved, let others know. This helps close the discussion and shows appreciation. It also lets others know the solution worked." - } - ], - "links": [ - { - "c": "github", - "a": ["gh", "opendevhub", "opendvh", "org"], - "r": "https://github.com/open-devhub" - } - ] -} +[ + { + "c": "askbetter", + "a": ["howtoask", "how2ask"], + "r": "**Ask Better Questions:** Include clear details about your problem: what you're trying to do, what you expected, what actually happened, and any relevant code or errors. This makes it much easier for others to help you.\nhttps://stackoverflow.com/help/how-to-ask" + }, + { + "c": "dontasktoask", + "a": ["ask", "justask"], + "r": "**Don't Ask to Ask:** Instead of asking if you can ask a question, just ask it directly. This helps others understand your issue right away.\nhttps://dontasktoask.com/" + }, + { + "c": "imageofanerror", + "a": ["imageoferror"], + "r": "**Avoid Images of Errors:** Please copy and paste the error message as text using code blocks. This makes it easier to read, search, and debug.\nhttps://idownvotedbecau.se/imageofatextualerror/" + }, + { + "c": "imageofcode", + "a": ["pictureofcode", "imgofcode"], + "r": "**Avoid Images of Code:** Share code as text in code blocks so others can read, copy, and test it. Images make this difficult.\nhttps://idownvotedbecau.se/imageofcode/" + }, + { + "c": "itsnotworking", + "a": ["itdoesntwork", "notworking", "doesntwork"], + "r": "**\"It's Not Working\" Isn't Enough:** Explain what you expected, what actually happened, and include relevant code or errors. More detail leads to better help.\nhttp://idownvotedbecau.se/itsnotworking/" + }, + { + "c": "mcve", + "r": "**Provide a Minimal Reproducible Example:** Share the smallest amount of code needed to reproduce your issue so others can quickly understand and test it.\nhttps://stackoverflow.com/help/minimal-reproducible-example" + }, + { + "c": "noattempt", + "r": "**Show Your Attempt:** Include what you've already tried. This helps others understand where you're stuck and avoids repeating suggestions.\nhttp://idownvotedbecau.se/noattempt/" + }, + { + "c": "nocode", + "a": ["showcode", "postcode"], + "r": "**No Code Provided:** It's difficult to help without seeing the relevant code. Please include the parts related to your issue.\nhttp://idownvotedbecau.se/nocode/" + }, + { + "c": "nodebug", + "a": ["nodebugging"], + "r": "**Try Debugging First:** Read error messages, add logs, and test parts of your code to narrow down the issue. Sharing your debugging steps helps others assist you.\nhttp://idownvotedbecau.se/nodebugging/" + }, + { + "c": "noerror", + "r": "**Include the Error Message:** If your code produces an error, share the full message. It often contains important clues.\nhttp://idownvotedbecau.se/noerror/" + }, + { + "c": "nohello", + "r": "**Don't Just Say Hello:** Ask your question directly instead of starting with only a greeting. This helps others respond more efficiently.\nhttps://www.nohello.net/" + }, + { + "c": "noresearch", + "a": ["research"], + "r": "**Do Some Research First:** Try searching or checking documentation before asking. If you still need help, mention what you've already looked at.\nhttp://idownvotedbecau.se/noresearch/" + }, + { + "c": "sask", + "r": "**Ask Directly:** Briefly describe your actual problem instead of asking if someone knows about a topic. This makes it easier to help right away." + }, + { + "c": "tldr", + "r": "**Keep It Concise:** Your message is quite long. Try summarizing the key points so others can understand your issue quickly." + }, + { + "c": "toomuchcode", + "r": "**Too Much Code:** Avoid sharing entire projects. Focus on the smallest portion of code that reproduces the issue.\nhttp://idownvotedbecau.se/toomuchcode/" + }, + { + "c": "toomuchinfo", + "r": "**Too Much Information:** Remove unrelated details and focus on what is directly relevant to your problem." + }, + { + "c": "tos", + "a": ["terms", "termsofservice", "discordtos", "guidelines", "guideline"], + "r": "**Community Guidelines:** https://discord.com/guidelines\n**Terms of Service:** https://discord.com/terms" + }, + { + "c": "tryit", + "a": ["tias"], + "r": "**Try It Yourself:** Experiment with your code or idea first. Testing things on your own is often the fastest way to learn and understand the issue." + }, + { + "c": "unclearquestion", + "a": ["unclear"], + "r": "**Unclear Question:** Please clarify what you're trying to do, include relevant code, and explain the issue more clearly.\nhttp://idownvotedbecau.se/unclearquestion/" + }, + { + "c": "xyproblem", + "a": ["xy"], + "r": "**The XY Problem:** You're asking about a specific solution instead of the actual problem. Explain your original goal so better solutions can be suggested.\nhttps://xyproblem.info/" + }, + + { + "c": "backseat", + "r": "**No Backseat Coding:** Avoid giving unsolicited advice or taking over someone else's troubleshooting unless they ask for it. It can confuse the person being helped and disrupt the flow of the conversation. Let the person helping guide the process." + }, + { + "c": "changesubjects", + "a": ["changesubject", "changetopic"], + "r": "**One Topic at a Time:** Avoid switching topics while someone is helping you with an issue. This makes it difficult to follow progress and can slow things down. Once your issue is resolved, you can start a new discussion." + }, + { + "c": "chatgpt", + "a": ["cursor", "claude", "copilot"], + "r": "**AI Usage:** AI tools can be helpful, but they may produce outdated or incorrect code. If you are sharing AI-generated code, please mention it and make sure you understand what it does. This helps others assist you more effectively." + }, + { + "c": "cheat", + "a": ["cheating"], + "r": "**No Cheating:** Do not ask for help with graded assignments, interviews, or anything involving academic or professional dishonesty. This community is here to help you learn, not to bypass the process. Focus on understanding the problem yourself." + }, + { + "c": "crypto", + "a": ["nft", "blockchain", "web3"], + "r": "**Crypto Policy:** This server does not provide support for cryptocurrency, NFTs, or blockchain-related projects. These topics are outside the scope of this community. Please use dedicated communities for that kind of help." + }, + { + "c": "dm", + "a": ["nodm", "nofriendreq", "nofriendrequest"], + "r": "**No Direct Messages for Help:** Keep help-related discussions in public channels. This allows others to learn from the conversation and lets multiple people assist if needed. It also keeps interactions transparent." + }, + { + "c": "english", + "r": "**English Only:** Please use English in this channel so moderators and members can understand and assist you. This ensures clear communication and avoids confusion. It also helps more people participate in the discussion." + }, + { + "c": "exams", + "a": ["noexams", "noactiveexams"], + "r": "**No Help with Active Exams:** Requests related to ongoing exams, certifications, or timed tests are not allowed. This includes anything that could be considered cheating. We encourage learning, not shortcuts." + }, + { + "c": "flame", + "a": ["toxic", "toxicity"], + "r": "**No Flaming or Toxicity:** Be respectful when interacting with others. Personal attacks, insults, or aggressive behavior are not allowed. Keep discussions constructive, even when you disagree." + }, + { + "c": "freework", + "a": ["labor"], + "r": "**No Requests for Free Work:** Do not ask others to build projects or features for you. This is a place to learn, not outsource work. Show what you have tried and ask for guidance instead." + }, + { + "c": "hacks", + "a": ["hacking", "cracking"], + "r": "**No Hacking or Exploits:** Do not discuss or request help with unauthorized access, exploits, or malicious activities. This includes bypassing security or abusing systems. Such topics are not allowed here." + }, + { + "c": "image", + "a": ["images"], + "r": "**Use Images Appropriately:** Avoid excessive or unnecessary images that disrupt the conversation. For code or errors, always use text and code blocks instead of screenshots. This makes it easier for others to read and help." + }, + { + "c": "moveon", + "a": ["cc"], + "r": "**Move On:** This discussion is no longer productive. Continuing it will not lead to a useful outcome. Please stop here and move to another topic." + }, + { + "c": "nickpolicy", + "a": ["nicknamepolicy", "nicknames"], + "r": "**Nickname Policy:** Use a readable and appropriate nickname. Avoid names that are hard to mention, misleading, or disruptive. Clear names make communication easier for everyone." + }, + { + "c": "noping", + "a": ["ping", "nopings"], + "r": "**No Unnecessary Pings:** Do not ping users or staff for general help. It can be disruptive and is usually unnecessary. Ask your question normally and wait for someone to respond." + }, + { + "c": "scraping", + "a": ["webscraping", "scrape", "automation"], + "r": "**Scraping Policy:** Make sure your automation follows the target site's rules and terms. Do not ask for help bypassing protections or scraping restricted platforms like Discord. Always keep your usage ethical and compliant." + }, + { + "c": "selfbot", + "a": ["selfbots"], + "r": "**No Self-Bots:** Automating a user account violates Discord's Terms of Service. This can lead to account termination. Discussion or support for self-bots is not allowed." + }, + { + "c": "spoon", + "a": ["spoonfeed", "spoonfeeding"], + "r": "**No Spoon-Feeding:** Focus on understanding the solution instead of copying it. We are here to guide you, not provide complete answers without effort. Learning the process is more valuable long-term." + }, + { + "c": "voice", + "a": ["vc"], + "r": "**Voice Channel Rules:** Keep your microphone clear and avoid background noise. Be respectful to others speaking and do not interrupt conversations. Maintain a comfortable environment for everyone." + }, + { + "c": "respecttime", + "a": ["patience", "wait"], + "r": "**Be Patient:** People here are volunteering their time to help. Avoid repeating your question or expecting instant replies. Someone will respond when they are available." + }, + { + "c": "nopressure", + "a": ["norush"], + "r": "**No Pressure:** Do not pressure others for quick answers. Marking things as urgent does not make them a priority here. Give people time to respond properly." + }, + { + "c": "formatcode", + "a": ["codeblock", "format"], + "r": "**Format Your Code:** Use proper code blocks with formatting and syntax highlighting when sharing code. This improves readability and reduces confusion. Well-formatted code is much easier to debug." + }, + { + "c": "correctchannel", + "a": ["wrongchannel", "channel"], + "r": "**Use the Correct Channel:** Post your question in the appropriate channel. This keeps discussions organized and ensures the right people see your message. It also improves your chances of getting help." + }, + { + "c": "duplicates", + "a": ["repeat", "repost"], + "r": "**No Duplicate Questions:** Do not repost the same question multiple times. This clutters the chat and makes it harder to help. If needed, update your original message instead." + }, + { + "c": "credits", + "a": ["credit", "attribution"], + "r": "**Give Credit:** If you use code or ideas from others, give proper credit. This shows respect and maintains trust within the community. It also helps others find the original source." + }, + { + "c": "nospam", + "a": ["spam"], + "r": "**No Spam:** Do not send repeated, irrelevant, or disruptive messages. This includes flooding channels or posting unnecessary content. Keep conversations meaningful." + }, + { + "c": "ads", + "a": ["advertising", "promo"], + "r": "**No Advertising:** Do not promote products, services, or servers without permission. Unsolicited promotion is not allowed. Keep the focus on discussion and help." + }, + { + "c": "safecontent", + "a": ["nsfw", "inappropriate"], + "r": "**Keep Content Appropriate:** Do not share explicit, unsafe, or inappropriate content. This includes anything that makes the space uncomfortable for others. Keep it suitable for everyone." + }, + { + "c": "privacy", + "a": ["dox", "doxxing"], + "r": "**Respect Privacy:** Do not share personal or sensitive information about yourself or others without permission. This includes private data or identifiable details. Respect boundaries at all times." + }, + { + "c": "piracy", + "a": ["warez", "cracked"], + "r": "**No Piracy:** Do not request or share pirated software, keys, or illegal downloads. This includes anything that bypasses licensing. Keep all activity legal." + }, + { + "c": "feedback", + "a": ["criticism"], + "r": "**Give Constructive Feedback:** When helping others, focus on being clear and respectful. Avoid dismissive or harsh responses. Helpful feedback should guide, not discourage." + }, + { + "c": "acknowledge", + "a": ["thanks", "resolved"], + "r": "**Acknowledge Help:** If your issue is resolved, let others know. This helps close the discussion and shows appreciation. It also lets others know the solution worked." + }, + + { + "c": "github", + "a": ["gh", "organization", "org"], + "r": "https://github.com/open-devhub" + }, + { + "c": "repo", + "a": ["repository"], + "r": "https://github.com/open-devhub/pandabot" + } +] diff --git a/src/events/clientReady/consoleLog.js b/src/events/clientReady/consoleLog.js deleted file mode 100644 index a74565c..0000000 --- a/src/events/clientReady/consoleLog.js +++ /dev/null @@ -1,3 +0,0 @@ -export default (client) => { - console.log(`${client.user.tag} is online.`); -}; diff --git a/src/events/clientReady/registerCommands.js b/src/events/clientReady/registerCommands.js deleted file mode 100644 index 4b0b3ba..0000000 --- a/src/events/clientReady/registerCommands.js +++ /dev/null @@ -1,99 +0,0 @@ -import { ApplicationCommandType } from "discord.js"; -import "dotenv/config"; -import path from "path"; -import { fileURLToPath, pathToFileURL } from "url"; -import data from "../../../config.json" with { type: "json" }; -import areCommandsDifferent from "../../utils/areCommandsDifferent.js"; -import getAllFiles from "../../utils/getAllFiles.js"; -import getApplicationCommands from "../../utils/getApplicationCommands.js"; -import getLocalCommands from "../../utils/getLocalCommands.js"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -const { guildId } = data; - -export default async (client) => { - if (process.env.REGISTER_COMMANDS == "false") { - console.log( - "[WARN] process.env.REGISTER_COMMANDS is set to false. Skipping slash command registration.", - ); - return; - } - try { - const localCommands = await getLocalCommands(); - const contextMenuCommands = []; - const contextMenuCategories = getAllFiles( - path.join(__dirname, "..", "..", "contextMenus"), - true, - ); - - for (const contextMenuCategory of contextMenuCategories) { - const contextMenuFiles = getAllFiles(contextMenuCategory); - - for (const file of contextMenuFiles) { - const mod = await import(pathToFileURL(file).href); - const command = (mod && mod.default) || mod; - contextMenuCommands.push(command); - } - } - - const allCommands = [...localCommands, ...contextMenuCommands]; - const applicationCommands = await getApplicationCommands(client, guildId); - - for (const localCommand of allCommands) { - const { name, description, options, type } = localCommand; - - const existingCommand = await applicationCommands.cache.find( - (cmd) => cmd.name === name, - ); - - if (existingCommand) { - if (localCommand.deleted) { - await applicationCommands.delete(existingCommand.id); - console.log(`πŸ—‘ Deleted command "${name}".`); - continue; - } - - if (areCommandsDifferent(existingCommand, localCommand)) { - const commandData = { name }; - if (type === undefined || type === ApplicationCommandType.ChatInput) { - commandData.description = description || "No description provided"; - if (Array.isArray(options) && options.length > 0) { - commandData.options = options; - } - } else { - commandData.type = type; - } - - await applicationCommands.edit(existingCommand.id, commandData); - - console.log(`πŸ” Edited command "${name}".`); - } - } else { - if (localCommand.deleted) { - console.log( - `⏩ Skipping registering command "${name}" as it's set to delete.`, - ); - continue; - } - - const commandData = { name }; - if (type === undefined || type === ApplicationCommandType.ChatInput) { - commandData.description = description || "No description provided"; - if (Array.isArray(options) && options.length > 0) { - commandData.options = options; - } - } else { - commandData.type = type; - } - - await applicationCommands.create(commandData); - - console.log(`πŸ‘ Registered command "${name}."`); - } - } - } catch (error) { - console.log(`There was an error in ${__filename}: ${error}`); - } -}; diff --git a/src/events/clientReady/setStatus.js b/src/events/clientReady/setStatus.js deleted file mode 100644 index 2207d4e..0000000 --- a/src/events/clientReady/setStatus.js +++ /dev/null @@ -1,24 +0,0 @@ -import { ActivityType } from "discord.js"; - -export default (client) => { - const setPresence = () => { - if (!client.user) return; - client.user.setPresence({ - activities: [ - { - name: "🐼 too lazy to load commands...", - type: ActivityType.Listening, - }, - ], - status: "online", - }); - }; - - setPresence(); - - if (client.presenceInterval) { - clearInterval(client.presenceInterval); - } - - client.presenceInterval = setInterval(setPresence, 60 * 60 * 1000); -}; diff --git a/src/events/guildMemberAdd/checkSuspended.js b/src/events/guildMemberAdd/checkSuspended.js deleted file mode 100644 index 534b2fc..0000000 --- a/src/events/guildMemberAdd/checkSuspended.js +++ /dev/null @@ -1,19 +0,0 @@ -import SuspendedMember from "../../models/SuspendedMember.js"; - -export default async (client, member) => { - try { - const record = await SuspendedMember.findOne({ - userId: member.id, - guildId: member.guild.id - }); - - if (!record) return; - - const suspendedRole = member.guild.roles.cache.get(record.roleId); - if (!suspendedRole) return; - - await member.roles.add(suspendedRole, "Evaded suspension by leaving and rejoining."); - } catch (error) { - console.error("Error checking persistent suspension:", error); - } -}; \ No newline at end of file diff --git a/src/events/guildMemberAdd/dm.js b/src/events/guildMemberAdd/dm.js deleted file mode 100644 index 1df8fb9..0000000 --- a/src/events/guildMemberAdd/dm.js +++ /dev/null @@ -1,36 +0,0 @@ -export default async (client, member) => { - if (!member || !member.id) return; - - try { - const guildName = member.guild?.name || "the server"; - const mention = member.user?.toString() || `<@${member.id}>`; - - const dmContent = `Hello ${mention}, πŸ‘‹ - -Welcome to **${guildName}**, we're glad to have you here. - -This community is a space for people who enjoy building, learning, and solving problems together. Whether you're just starting out or already experienced, you'll find others here to connect with and learn from. - -Feel free to: -- Share projects you're working on or ideas you're developing -- Ask for help if you run into issues or get stuck -- Contribute knowledge or insights in discussions -- Collaborate and exchange ideas with other members -- Explore tools, technologies, and best practices together - -Take some time to look around and get familiar with the channels. If you need anything or have questions, don't hesitate to ask. -Welcome aboard, we’re looking forward to seeing what you create πŸš€ -`; - - // attempt to dm tha new member, users may have dms from server members disabled - await member.user.send({ content: dmContent }).catch((err) => { - const msg = `Could not send welcome DM to ${ - member.user.tag || member.id - }: ${err?.message || err}`; - if (client?.logger?.info) client.logger.info(msg); - else console.warn(msg); - }); - } catch (err) { - console.error("Error sending welcome DM on guildMemberAdd:", err); - } -}; diff --git a/src/events/guildMemberAdd/sendWelcomeMessage.js b/src/events/guildMemberAdd/sendWelcomeMessage.js deleted file mode 100644 index f7f7d8a..0000000 --- a/src/events/guildMemberAdd/sendWelcomeMessage.js +++ /dev/null @@ -1,36 +0,0 @@ -import { EmbedBuilder } from "discord.js"; -import data from "../../../config.json" with { type: "json" }; - -const { serverConfig } = data; - -export default async (client, member) => { - if (!member || !member.id) return; - - try { - const guildName = member.guild?.name || "the server"; - const mention = member.user?.toString() || `<@${member.id}>`; - const welcomeChannelId = serverConfig.welcomeChannel; - - const welcomeEmbed = new EmbedBuilder() - .setColor(0x11dd44) - .setTitle(`Welcome to ${guildName}, ${member.user.username}! πŸŽ‰`) - .setDescription( - `Welcome ${mention}! We're delighted to have you join us in **${guildName}**.\n` + - `Take a moment to explore the channels, introduce yourself, and connect with the community.\n` + - `Once again, a warm welcome aboard β€” we look forward to your contributions and conversations! 🌟`, - ) - .setThumbnail(member.user.displayAvatarURL({ dynamic: true })) - .setTimestamp(); - - const welcomeChannel = member.guild.channels.cache.get(welcomeChannelId); - if (welcomeChannel) { - await welcomeChannel.send({ embeds: [welcomeEmbed] }); - } else { - console.warn( - `Welcome channel with ID ${welcomeChannelId} not found in guild ${guildName}.`, - ); - } - } catch (err) { - console.error("Error sending welcome message on guildMemberAdd:", err); - } -}; diff --git a/src/events/guildMemberRemove/clearMDBDocuments.js b/src/events/guildMemberRemove/clearMDBDocuments.js deleted file mode 100644 index 0a2f387..0000000 --- a/src/events/guildMemberRemove/clearMDBDocuments.js +++ /dev/null @@ -1,16 +0,0 @@ -import Counting from "../../models/Counting.js"; -import Profile from "../../models/Profile.js"; - -export default async (client, member) => { - if (!member || !member.id) return; - - try { - await Counting.findOneAndDelete({ userId: member.id }); - await Profile.findOneAndDelete({ userId: member.id }); - } catch (err) { - console.error( - "Error removing MongoDB documents on guildMemberRemove:", - err, - ); - } -}; diff --git a/src/events/interactionCreate/handleCommands.js b/src/events/interactionCreate/handleCommands.js deleted file mode 100644 index 412d6fa..0000000 --- a/src/events/interactionCreate/handleCommands.js +++ /dev/null @@ -1,90 +0,0 @@ -import path from "path"; -import { fileURLToPath, pathToFileURL } from "url"; -import data from "../../../config.json" with { type: "json" }; -import getAllFiles from "../../utils/getAllFiles.js"; -import getLocalCommands from "../../utils/getLocalCommands.js"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -const { devs, guildId } = data; - -export default async (client, interaction) => { - if (!interaction.isCommand()) return; - - const localCommands = await getLocalCommands(); - const contextMenuCommands = []; - const contextMenuCategories = getAllFiles( - path.join(__dirname, "..", "..", "contextMenus"), - true, - ); - - for (const contextMenuCategory of contextMenuCategories) { - const contextMenuFiles = getAllFiles(contextMenuCategory); - - for (const file of contextMenuFiles) { - const command = await import(pathToFileURL(file).href); - contextMenuCommands.push(command); - } - } - - const allCommands = [...localCommands, ...contextMenuCommands]; - - try { - const commandObject = allCommands.find( - (cmd) => cmd.name === interaction.commandName, - ); - - if (!commandObject) return; - - if (commandObject.devOnly) { - if (!devs.includes(interaction.member.id)) { - interaction.reply({ - content: "Only developers are allowed to run this command.", - ephemeral: true, - }); - return; - } - } - - if (commandObject.testOnly) { - if (!(interaction.guild.id === guildId)) { - interaction.reply({ - content: "This command cannot be ran here.", - ephemeral: true, - }); - return; - } - } - - if (commandObject.permissionsRequired?.length) { - for (const permission of commandObject.permissionsRequired) { - if (!interaction.member.permissions.has(permission)) { - interaction.reply({ - content: "Not enough permissions.", - ephemeral: true, - }); - return; - } - } - } - - if (commandObject.botPermissions?.length) { - for (const permission of commandObject.botPermissions) { - const bot = interaction.guild.members.me; - - if (!bot.permissions.has(permission)) { - interaction.reply({ - content: "I don't have enough permissions.", - ephemeral: true, - }); - return; - } - } - } - - await commandObject.callback(client, interaction); - } catch (error) { - console.log(`There was an error running this command: ${error}`); - } -}; diff --git a/src/events/interactionCreate/handleInteractions.js b/src/events/interactionCreate/handleInteractions.js deleted file mode 100644 index 6cf384b..0000000 --- a/src/events/interactionCreate/handleInteractions.js +++ /dev/null @@ -1,32 +0,0 @@ -import { fileURLToPath , pathToFileURL } from "url"; -import path from "path"; -import getAllFiles from "../../utils/getAllFiles.js"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -const interactions = []; -const interactionFiles = getAllFiles( - path.join(__dirname, "..", "..", "interactions"), -); -for (const file of interactionFiles) { - const mod = await import(pathToFileURL(file).href); - const command = (mod && mod.default) || mod; - interactions.push(command); -} - -export default async (client, interaction) => { - try { - const interactionObject = interactions.find( - (cmd) => cmd?.id === interaction.customId, - ); - - if (!interactionObject) return; - - if (typeof interactionObject.callback === "function") { - await interactionObject.callback(client, interaction); - } - } catch (error) { - console.log(`There was an error running this command: ${error}`); - } -}; diff --git a/src/events/messageCreate/afk.js b/src/events/messageCreate/afk.js deleted file mode 100644 index f38d08e..0000000 --- a/src/events/messageCreate/afk.js +++ /dev/null @@ -1,50 +0,0 @@ -import { EmbedBuilder } from "discord.js"; -import { afks } from "../../states/afk.js"; - -export default async (client, message) => { - if (!message.guild || message.author.bot) return; - - if (afks.has(message.author.id)) { - const embed = new EmbedBuilder() - .setAuthor({ - name: message.author.tag, - iconURL: message.author.displayAvatarURL(), - }) - .setTitle("AFK Status Removed") - .setDescription("Welcome back! Your AFK status has been removed.") - // compare timestamp - .setFooter({ - text: `You were AFK for ${Math.floor( - (Date.now() - - new Date(afks.get(message.author.id).timestamp).getTime()) / - 1000 / - 60, - )} minutes.`, - }) - .setColor(0x2b2d31); - const reply = await message.reply({ embeds: [embed] }); - afks.delete(message.author.id); - setTimeout(() => { - reply.delete().catch(() => {}); - }, 5000); - return; - } - - const mentionedAfks = message.mentions.users.filter((user) => - afks.has(user.id), - ); - - if (mentionedAfks.size > 0) { - const descriptions = mentionedAfks.map((user) => { - const reason = afks.get(user.id).reason; - return `**${user.toString()}** is AFK${reason ? `: ${reason}` : ""}.`; - }); - - const embed = new EmbedBuilder() - .setTitle("AFK Status") - .setDescription(descriptions.join("\n")) - .setColor(0x2b2d31); - - message.reply({ embeds: [embed] }); - } -}; diff --git a/src/events/messageCreate/counting.js b/src/events/messageCreate/counting.js deleted file mode 100644 index ce732cc..0000000 --- a/src/events/messageCreate/counting.js +++ /dev/null @@ -1,210 +0,0 @@ -import data from "../../../config.json" with { type: "json" }; -import Counting from "../../models/Counting.js"; -import { counts } from "../../states/counting.js"; - -const { serverConfig } = data; - -export default async (client, message) => { - try { - if (!message?.guild) return; - if (message.author?.bot) return; - - const channel = message.channel; - const guildId = message.guild.id; - const key = `${guildId}-${channel.id}`; - - if (channel.id !== serverConfig.countingChannel) return; - - const content = message.content.trim(); - let num = null; - - if (/^[0-9]+$/.test(content)) { - num = parseInt(content, 10); - } else if (/^[0-9+\-*/().%\s^]+$/.test(content)) { - try { - const safeExpr = content.replace(/\^/g, "**"); - if (/([+\-*/%^]{2,})/.test(safeExpr.replace(/\s+/g, ""))) return; - - const res = Function(`"use strict"; return (${safeExpr})`)(); - if ( - typeof res === "number" && - Number.isFinite(res) && - Number.isInteger(res) - ) { - num = res; - } else return; - } catch { - return; - } - } else { - return; - } - - const raw = counts.get(key); - const state = { - lastNum: raw?.lastNum ?? 0, - lastUser: raw?.lastUser ?? null, - saves: raw?.saves ?? 0, - }; - - if (state.lastNum === 0) { - if (num === 1) { - counts.set(key, { - lastNum: 1, - lastUser: message.author.id, - saves: 0, - }); - - let count = await Counting.findOne({ userId: message.author.id }); - - if (!count) { - count = new Counting({ userId: message.author.id, counts: 1 }); - } else { - count.counts += 1; - } - - await count.save().catch((err) => { - console.error("Error saving count to database:", err); - }); - - await message.react("βœ…").catch(() => {}); - return; - } else { - counts.set(key, { lastNum: 0, lastUser: null, saves: 0 }); - - await message.channel.send( - `${message.author}, the count should start at **1**. Counter has been reset.`, - ); - return; - } - } - - if (message.author.id === state.lastUser) { - await message.channel.send( - `${message.author}, you can't count twice in a row.`, - ); - message.react("πŸ’’").catch(() => {}); - return; - } - - if (num === state.lastNum + 1) { - let newSaves = state.saves; - - try { - switch (num) { - case 25: - await message.react("🌟"); - break; - case 50: - await message.react("😎"); - break; - case 75: - await message.react("✨"); - break; - case 100: - newSaves += 5; - await message.channel.send( - `We've reached **100** counts! +5 saves have been added!`, - ); - await message.react("πŸ’―"); - await message.react("πŸ†"); - break; - case 150: - await message.react("πŸŽ‰"); - break; - case 200: - await message.react("πŸ₯³"); - break; - case 250: - await message.react("πŸš€"); - break; - case 300: - await message.react("πŸŒ•"); - break; - case 400: - await message.react("πŸŽ†"); - break; - case 500: - newSaves += 3; - await message.channel.send( - `+3 saves have been added! Let's keep going!`, - ); - await message.react("πŸ‘‘"); - break; - case 750: - await message.react("🀩"); - break; - case 1000: - newSaves += 10; - await message.channel.send( - `Incredible! We've reached **1000** counts! πŸŽ‰πŸ†`, - ); - await message.channel.send( - `+10 saves have been added! Let's keep going!`, - ); - await message.react("πŸ…"); - await message.react("πŸ†"); - await message.react("πŸŽ‰"); - break; - default: - await message.react("βœ…"); - } - } catch {} - - counts.set(key, { - lastNum: num, - lastUser: message.author.id, - saves: newSaves, - }); - - let count = await Counting.findOne({ userId: message.author.id }); - - if (!count) { - count = new Counting({ userId: message.author.id, counts: 1 }); - } else { - count.counts += 1; - } - - await count.save().catch((err) => { - console.error("Error saving count to database:", err); - }); - - return; - } - - if (state.saves && state.saves > 0) { - const newSaves = state.saves - 1; - - counts.set(key, { - lastNum: state.lastNum, - lastUser: state.lastUser, - saves: newSaves, - }); - - await message.channel.send( - `${message.author}, wrong number β€” expected **${ - state.lastNum + 1 - }**. You have **${newSaves}** save${ - newSaves === 1 ? "" : "s" - } left before reset.`, - ); - return; - } - - const expected = state.lastNum + 1; - - counts.set(key, { - lastNum: 0, - lastUser: null, - saves: 0, - }); - - await message.channel.send( - `${message.author}, wrong number β€” expected **${expected}**. Counter reset. Next number should be **1**.`, - ); - - message.react("❌").catch(() => {}); - } catch (err) { - console.error("Counting handler error:", err); - } -}; diff --git a/src/events/messageCreate/handleMacros.js b/src/events/messageCreate/handleMacros.js deleted file mode 100644 index 3eea044..0000000 --- a/src/events/messageCreate/handleMacros.js +++ /dev/null @@ -1,56 +0,0 @@ -import data from "../../../config.json" with { type: "json" }; -import macros from "../../data/macros.json" with { type: "json" }; - -const { macroPrefixes } = data; - -const COOLDOWN_SECONDS = 3; -const USER_COOLDOWNS = new Map(); - -export default async (client, message) => { - if (!message || !message.guild || message.author?.bot) return; - - const now = Date.now(); - const expiry = USER_COOLDOWNS.get(message.author.id); - if (expiry && expiry > now) { - return; - } - - try { - const prefix = macroPrefixes.find((p) => message.content.startsWith(p)); - if (!prefix) return; - - const expireAt = Date.now() + COOLDOWN_SECONDS * 1000; - USER_COOLDOWNS.set(message.author.id, expireAt); - setTimeout( - () => USER_COOLDOWNS.delete(message.author.id), - COOLDOWN_SECONDS * 1000, - ); - - const args = message.content.slice(prefix.length).trim().split(/ +/); - const commandName = args.shift().toLowerCase(); - const macroCategories = Object.keys(macros); - - let response = null; - for (const category of macroCategories) { - const categoryMacros = macros[category]; - const macro = categoryMacros.find((m) => { - if (!m || !m.c) return false; - if (String(m.c).toLowerCase() === commandName) return true; - if (Array.isArray(m.a)) { - return m.a.map((a) => String(a).toLowerCase()).includes(commandName); - } - return false; - }); - if (macro) { - response = macro.r; - break; - } - } - - if (response) { - await message.channel.send({ content: response }); - } - } catch (err) { - console.error("Prefix Command Error:", err); - } -}; diff --git a/src/events/messageCreate/handlePrefixCommands.js b/src/events/messageCreate/handlePrefixCommands.js deleted file mode 100644 index 7f59ca4..0000000 --- a/src/events/messageCreate/handlePrefixCommands.js +++ /dev/null @@ -1,81 +0,0 @@ -import path from "path"; -import { fileURLToPath , pathToFileURL } from "url"; -import data from "../../../config.json" with { type: "json" }; -import getAllFiles from "../../utils/getAllFiles.js"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -const { prefixes } = data; - -const COOLDOWN_SECONDS = 3; -const USER_COOLDOWNS = new Map(); - -export default async (client, message) => { - if (!message || !message.guild || message.author?.bot) return; - - const now = Date.now(); - const expiry = USER_COOLDOWNS.get(message.author.id); - if (expiry && expiry > now) { - return; - } - - try { - const prefix = prefixes.find((p) => message.content.startsWith(p)); - if (!prefix) return; - - const expireAt = Date.now() + COOLDOWN_SECONDS * 1000; - USER_COOLDOWNS.set(message.author.id, expireAt); - setTimeout( - () => USER_COOLDOWNS.delete(message.author.id), - COOLDOWN_SECONDS * 1000, - ); - - const args = message.content.slice(prefix.length).trim().split(/ +/); - const commandName = args.shift().toLowerCase(); - const prefixCommandsPath = path.join( - __dirname, - "..", - "..", - "prefixCommands", - ); - - const prefixCommandsCategories = getAllFiles(prefixCommandsPath, true); - const prefixCommands = []; - - for (const category of prefixCommandsCategories) { - const commandFiles = getAllFiles(category); - for (const file of commandFiles) { - const mod = await import(pathToFileURL(file).href); - const command = (mod && mod.default) || mod; - prefixCommands.push(command); - } - } - - const commandObject = prefixCommands.find((cmd) => { - if (!cmd || !cmd.name) return false; - if (String(cmd.name).toLowerCase() === commandName) return true; - if (Array.isArray(cmd.aliases)) { - return cmd.aliases - .map((a) => String(a).toLowerCase()) - .includes(commandName); - } - return false; - }); - if (!commandObject) return; - - if (commandObject.permissionsRequired?.length) { - for (const permission of commandObject.permissionsRequired) { - if (!message.member.permissions.has(permission)) { - message.reply("Not enough permissions to run this command."); - return; - } - } - } - if (typeof commandObject.callback === "function") { - await commandObject.callback(client, message, args); - } - } catch (err) { - console.error("Prefix Command Error:", err); - } -}; diff --git a/src/events/messageCreate/handleVerification.js b/src/events/messageCreate/handleVerification.js deleted file mode 100644 index f7d8592..0000000 --- a/src/events/messageCreate/handleVerification.js +++ /dev/null @@ -1,33 +0,0 @@ -import data from "../../../config.json" with { type: "json" }; -import Verification from "../../models/Verification.js"; - -const { serverConfig } = data; - -export default async (client, message) => { - if (message.guild || message.author.bot) return; - - const activeVerification = await Verification.findOne({ userId: message.author.id }); - if (!activeVerification) return; - - const targetGuild = client.guilds.cache.get(activeVerification.guildId); - if (!targetGuild) return; - - const member = await targetGuild.members.fetch(message.author.id).catch(() => null); - const suspendedRole = targetGuild.roles.cache.get(serverConfig.suspendedRoleId); - - if (!member || !suspendedRole) return; - - if (message.content.trim().toLowerCase() === activeVerification.captchaAnswer.toLowerCase()) { -try { - await member.roles.remove(suspendedRole, "Passed manual text verification captcha."); - - await Verification.deleteOne({ userId: message.author.id }); - await message.reply("βœ… Verification successful! Your server access has been completely restored."); -} catch (err) { - console.error(`Verification error for user ${message.author.id}:`, err); - await message.reply("❌ Verification failed due to a server error. Please try again or contact a moderator."); -} - } else { - await message.reply("❌ Incorrect code. Please look at the image carefully and try typing it again."); -} -}; diff --git a/src/events/messageCreate/introductions.js b/src/events/messageCreate/introductions.js deleted file mode 100644 index 0c94c13..0000000 --- a/src/events/messageCreate/introductions.js +++ /dev/null @@ -1,46 +0,0 @@ -import data from "../../../config.json" with { type: "json" }; - -const { serverConfig } = data; - -export default async (client, message) => { - if (!message || !message.guild || message.author?.bot) return; - - const channel = message.channel; - if (channel.id !== serverConfig.introductionsChannel) return; - - const stickyMessageContent = - "**Welcome to DevHub!** Please introduce yourself by sharing your preferred name/nickname, favorite languages/tools/frameworks, areas of interest, hobbies outside tech, and what you hope to learn or contribute here. We’re excited you’re here!"; - - try { - const fetched = await channel.messages.fetch({ limit: 10 }); - - const stickies = fetched.filter( - (msg) => - msg.author.id === client.user.id && - msg.content === stickyMessageContent, - ); - - for (const msg of stickies.values()) { - await msg.delete().catch(() => {}); - } - - await channel.send(stickyMessageContent); - } catch (err) { - console.error("Sticky refresh error:", err); - } - - try { - if (message.reference) return; - await message.react("πŸ‘‹").catch(() => {}); - - const welcomeEmojiId = serverConfig.emojis?.welcomeEmoji; - if (welcomeEmojiId) { - const customEmoji = message.guild.emojis.cache.get(welcomeEmojiId); - if (customEmoji) { - await message.react(customEmoji).catch(() => {}); - } - } - } catch (err) { - console.error("Intro reaction error:", err); - } -}; diff --git a/src/events/messageCreate/mentionrule.js b/src/events/messageCreate/mentionrule.js deleted file mode 100644 index fc885d0..0000000 --- a/src/events/messageCreate/mentionrule.js +++ /dev/null @@ -1,35 +0,0 @@ -import { EmbedBuilder } from "discord.js"; -import data from "../../../config.json" with { type: "json" }; -import rules from "../../data/rules.json" with { type: "json" }; - -const { prefixes } = data; - -export default async (client, message) => { - if (!message.guild || message.author.bot) return; - - const prefixUsed = prefixes.find((prefix) => - message.content.toLowerCase().startsWith(prefix.toLowerCase()), - ); - if (!prefixUsed) return; - - const ruleNum = message.content.slice(prefixUsed.length).trim().toLowerCase(); - if (!/^r\d+$/.test(ruleNum)) return; - - const ruleIndex = parseInt(ruleNum.slice(1), 10) - 1; - if (ruleIndex < 0 || ruleIndex >= rules.length) return; - - const rule = rules[ruleIndex]; - if (!rule) return; - - try { - const description = rule.pts.map((pt) => `↳ ${pt}`).join("\n"); - - const embed = new EmbedBuilder() - .setTitle(`πŸ“œ ${rule.t}`) - .setDescription(description) - .setColor(0x5865f2); - message.channel.send({ embeds: [embed] }); - } catch (err) { - console.error(err); - } -}; diff --git a/src/events/messageDelete/countdelete.js b/src/events/messageDelete/countdelete.js deleted file mode 100644 index e68a6d4..0000000 --- a/src/events/messageDelete/countdelete.js +++ /dev/null @@ -1,26 +0,0 @@ -import data from "../../../config.json" with { type: "json" }; -import { counts } from "../../states/counting.js"; - -const { serverConfig } = data; - -export default async (client, message) => { - try { - if (!message?.guild) return; - if (message.author?.bot) return; - - const channel = message.channel; - if (channel.id !== serverConfig.countingChannel) return; - const guildId = message.guild.id; - const key = `${guildId}-${channel.id}`; - - if (parseInt(message.content) !== counts.get(key)?.lastNum) return; - - await message.channel - .send( - `Hey ${message.author}, please don't delete your counting messages! The current count is **${counts.get(key)?.lastNum || 0}**.`, - ) - .catch(() => {}); - } catch (err) { - console.error("Counting handler error:", err); - } -}; diff --git a/src/events/messageReactionAdd/starboard.js b/src/events/messageReactionAdd/starboard.js deleted file mode 100644 index 3882e64..0000000 --- a/src/events/messageReactionAdd/starboard.js +++ /dev/null @@ -1,102 +0,0 @@ -import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - EmbedBuilder, -} from "discord.js"; -import data from "../../../config.json" with { type: "json" }; - -const { serverConfig } = data; - -export default async (client, reaction) => { - try { - if (reaction.partial) await reaction.fetch(); - if (reaction.message.partial) await reaction.message.fetch(); - - const message = reaction.message; - if (!message.guild) return; - if (message.author?.bot) return; - - const allowedEmojis = [ - "⭐", - "🌟", - "πŸ’€", - "🀣", - "πŸ˜‚", - "😹", - "❀️", - "😍", - "😻", - "πŸ”₯", - "πŸ’―", - "🀩", - ]; - - const { starboardChannel, starboardExclude } = serverConfig; - const { categories, channels } = starboardExclude; - const reactionRequired = 4; - - const channel = message.guild.channels.cache.get(starboardChannel); - if (!channel) return; - if (Object.values(channels).includes(message.channel.id)) return; - if (Object.values(categories).includes(message.channel.parentId)) return; - - const validReactions = message.reactions.cache.filter( - (r) => - allowedEmojis.includes(r.emoji.name) && r.count >= reactionRequired, - ); - - if (validReactions.size === 0) return; - - const chosen = validReactions.sort((a, b) => b.count - a.count).first(); - - const existing = await channel.messages.fetch({ limit: 15 }); - if (existing.find((m) => m.embeds[0]?.footer?.text.includes(message.id))) - return; - - const embed = new EmbedBuilder() - .setColor(0xffd700) - .setAuthor({ - name: message.author.tag, - iconURL: message.author.displayAvatarURL({ dynamic: true }), - }) - .setDescription( - `**${chosen.emoji.toString()} ${chosen.count}**\n` + - `${message.content ? `> ${message.content}` : "> *No text message*"}`, - ) - .addFields( - { name: "Author", value: `<@${message.author.id}>`, inline: true }, - { name: "Channel", value: `<#${message.channel.id}>`, inline: true }, - ) - .setFooter({ text: `${message.id}` }) - .setTimestamp(message.createdAt); - - if (message.attachments.size > 0) { - const attachment = message.attachments.first(); - if (attachment.contentType?.startsWith("image")) { - embed.setImage(attachment.url); - } else { - embed.addFields({ - name: "Attachment", - value: `[Download File](${attachment.url})`, - }); - } - } - - const row = new ActionRowBuilder().addComponents( - new ButtonBuilder() - .setLabel("Jump to Message") - .setStyle(ButtonStyle.Link) - .setURL(message.url), - ); - - const sent = await channel.send({ - embeds: [embed], - components: [row], - }); - - await sent.react(chosen.emoji.toString()); - } catch (err) { - console.error("Starboard error:", err); - } -}; diff --git a/src/handlers/eventHandler.js b/src/handlers/eventHandler.js deleted file mode 100644 index 88e07a7..0000000 --- a/src/handlers/eventHandler.js +++ /dev/null @@ -1,33 +0,0 @@ -import path from "path"; -import { fileURLToPath, pathToFileURL } from "url"; -import getAllFiles from "../utils/getAllFiles.js"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -export default (client) => { - const eventFolders = getAllFiles(path.join(__dirname, "..", "events"), true); - - for (const eventFolder of eventFolders) { - let eventFiles = getAllFiles(eventFolder); - eventFiles.sort(); - - const eventName = eventFolder.replace(/\\/g, "/").split("/").pop(); - - client.on(eventName, async (...args) => { - for (const eventFile of eventFiles) { - const fixedPath = path.resolve(eventFile).replace(/^[a-z]:/, (match) => match.toUpperCase()); - const eventModule = await import(pathToFileURL(fixedPath).href); - const eventFunction = - (eventModule && (eventModule.default || eventModule.execute)) || - eventModule; - - if (typeof eventFunction === "function") { - await eventFunction(client, ...args); - } else { - continue; - } - } - }); - } -}; diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 58cbcfc..0000000 --- a/src/index.js +++ /dev/null @@ -1,64 +0,0 @@ -import { Client, IntentsBitField, Partials } from "discord.js"; -import "dotenv/config"; -import mongoose from "mongoose"; -import eventHandler from "./handlers/eventHandler.js"; - -const client = new Client({ - intents: [ - IntentsBitField.Flags.Guilds, - IntentsBitField.Flags.GuildMembers, - IntentsBitField.Flags.GuildMessages, - IntentsBitField.Flags.GuildPresences, - IntentsBitField.Flags.MessageContent, - IntentsBitField.Flags.GuildMessageReactions, - IntentsBitField.Flags.DirectMessages, - ], - partials: [Partials.Message, Partials.Channel, Partials.Reaction], -}); - -(async () => { - try { - const uri = process.env.MONGODB_URI; - if (!uri) { - console.error( - "Missing MONGODB_URI in environment. Please set it in .env or environment variables.", - ); - process.exit(1); - } - - console.log("Connecting to MongoDB..."); - - mongoose.set("strictQuery", false); - mongoose.connection.on("error", (err) => { - console.error( - "Mongoose connection error:", - err && err.message ? err.message : err, - ); - }); - - await mongoose.connect(uri, { - serverSelectionTimeoutMS: 10000, - }); - - console.log("Connected to DB."); - - eventHandler(client); - - client.login(process.env.TOKEN).catch((err) => { - console.error("Discord login error:", err); - }); - - client.on("error", console.error); - client.on("shardError", console.error); - } catch (err) { - console.error(err); - } -})(); - -process.on("unhandledRejection", (reason, promise) => { - console.error("Unhandled Rejection at:", promise, "reason:", reason); -}); - -process.on("uncaughtException", (err) => { - console.error("Uncaught Exception thrown:", err); -}); diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..ec1fa22 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,34 @@ +import { + ApplicationCommandRegistries, + SapphireClient, +} from "@sapphire/framework"; +import { getRootData } from "@sapphire/pieces"; +import "@sapphire/plugin-editable-commands/register"; +import { GatewayIntentBits, Partials } from "discord.js"; +import { join } from "path"; +import { config } from "./config/app.ts"; +import { env } from "./config/env.ts"; + +// only register commands in the single server +ApplicationCommandRegistries.setDefaultGuildIds([config.settings.serverId]); + +export const client = new SapphireClient({ + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMembers, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.MessageContent, + GatewayIntentBits.GuildMessageReactions, + ], + partials: [Partials.Channel, Partials.Message, Partials.Reaction], + + defaultPrefix: config.settings.prefixes.commands, + loadMessageCommandListeners: true, +}); + +// scan for /interactions instead of /interaction-handler +client.stores + .get("interaction-handlers") + .registerPath(join(getRootData().root, "interactions")); + +client.login(env.BOT_TOKEN); diff --git a/src/interactions/closeTicket.js b/src/interactions/closeTicket.js deleted file mode 100644 index 58d02c0..0000000 --- a/src/interactions/closeTicket.js +++ /dev/null @@ -1,182 +0,0 @@ -import { EmbedBuilder, PermissionFlagsBits } from "discord.js"; - -import data from "../../config.json" with { type: "json" }; -import buildModal from "../utils/buildModal.js"; -import buildTicketTranscript from "../utils/buildTicketTranscript.js"; - -const { serverConfig } = data; - -export default { - id: "close_ticket", - callback: async (client, interaction) => { - const { database, transcripts } = serverConfig.tickets; - const { moderatorRoleId } = serverConfig; - - const member = interaction.member; - const isOpener = interaction.message.embeds[0]?.footer?.text?.includes( - interaction.user.id, - ); - const isModerator = - moderatorRoleId && member.roles.cache.has(moderatorRoleId); - const isAdmin = member.permissions.has(PermissionFlagsBits.Administrator); - - if (!isOpener && !isModerator && !isAdmin) { - await interaction.reply({ - content: "You are not allowed to close this ticket.", - ephemeral: true, - }); - return; - } - - const closeModalId = `close_ticket_modal_${interaction.user.id}_${Date.now()}`; - const closeModal = buildModal(client, { - customId: closeModalId, - title: "Close Ticket", - fields: [ - { - customId: "reason", - label: "Reason", - style: "PARAGRAPH", - placeholder: "Explain why this ticket is being closed (optional)", - required: false, - maxLength: 1024, - }, - ], - }); - - try { - await interaction.showModal(closeModal); - } catch (err) { - console.error("Failed to show close modal:", err); - await interaction - .reply({ - content: "Failed to open close form. Please try again.", - ephemeral: true, - }) - .catch(() => {}); - return; - } - - let closeSubmit; - try { - closeSubmit = await interaction.awaitModalSubmit({ - filter: (m) => - m.user.id === interaction.user.id && m.customId === closeModalId, - time: 300000, - }); - } catch (err) { - console.error("Close modal submit error or timeout:", err); - await interaction - .followUp({ - content: "You did not submit the close form in time.", - ephemeral: true, - }) - .catch(() => {}); - return; - } - - const closeReason = closeSubmit.fields.getTextInputValue("reason") || ""; - - await closeSubmit - .reply({ content: "Closing ticket...", ephemeral: true }) - .catch(() => {}); - - const safeName = interaction.channel.name; - - const id = safeName.split("-")[1]; - - // transcript - try { - const databaseChannel = await client.channels.fetch(database); - const transcriptsChannel = await client.channels.fetch(transcripts); - - const fetchedMessages = await interaction.channel.messages.fetch({ - limit: 100, - }); - const sortedMessages = fetchedMessages.sort( - (a, b) => a.createdTimestamp - b.createdTimestamp, - ); - - const messagesData = []; - for (const msg of sortedMessages.values()) { - if (msg.author.bot) continue; // exclude bot messages - const attachments = []; - for (const attach of msg.attachments.values()) { - if (attach.contentType?.startsWith("image/")) { - const sent = await databaseChannel.send({ - files: [ - { - attachment: attach.url, - name: attach.name || "image.png", - }, - ], - }); - attachments.push(sent.attachments.first().url); - } - } - messagesData.push({ - id: msg.id, - authorId: msg.author.id, - content: msg.content, - timestamp: msg.createdTimestamp, - attachments, - reference: msg.reference, - }); - } - - const html = await buildTicketTranscript(client, messagesData); - await transcriptsChannel.send({ - content: `Ticket ID: ${id}`, - files: [ - { - attachment: Buffer.from(html), - name: `transcript-${safeName}.html`, - }, - ], - }); - } catch (e) { - console.error("Failed to generate transcript:", e); - } - - try { - await interaction.channel.delete( - `Ticket closed by ${interaction.user.tag}`, - ); - const dmContent = new EmbedBuilder() - .setTitle("Ticket Closed") - .setDescription( - `Your ticket "${safeName}" has been closed. If you have further questions, feel free to open a new ticket.`, - ) - .setFields( - // partnership-xxxxx -> partnership, slice off the id - { name: "Type", value: safeName.split("-")[0], inline: true }, - { name: "ID", value: id, inline: true }, - { - name: "Closed By", - value: interaction.user.toString(), - inline: true, - }, - - { - name: "Reason", - value: closeReason || "No reason provided", - inline: false, - }, - ) - .setColor(0x11ee11) - .setFooter({ - text: `Closed at ${new Date().toLocaleString()}`, - iconURL: client.user.displayAvatarURL(), - }) - .setTimestamp(); - - const opener = await client.users.fetch( - interaction.message.embeds[0].footer.text, - ); - - await opener.send({ embeds: [dmContent] }).catch(() => {}); - } catch (e) { - console.error("Failed to delete ticket channel:", e); - } - }, -}; diff --git a/src/interactions/createTicket.js b/src/interactions/createTicket.js deleted file mode 100644 index a0a4d5c..0000000 --- a/src/interactions/createTicket.js +++ /dev/null @@ -1,269 +0,0 @@ -import crypto from "crypto"; -import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - ChannelType, - EmbedBuilder, - PermissionFlagsBits, -} from "discord.js"; -import data from "../../config.json" with { type: "json" }; -import buildModal from "../utils/buildModal.js"; - -const { serverConfig } = data; - -const selectMenu = [ - { - label: "🧩 General Support", - value: "support", - fields: [ - { - customId: "reason", - label: "What do you need help with?", - style: "PARAGRAPH", - placeholder: "Explain what you need help with", - required: true, - maxLength: 1024, - }, - ], - }, - { - label: "🎭 Request Unban / Unmute", - value: "appeal", - fields: [ - { - customId: "reason", - label: "Reason", - style: "PARAGRAPH", - placeholder: "Explain why you are requesting unban/unmute", - required: true, - maxLength: 1024, - }, - ], - }, - { - label: "🚨 Report User", - value: "report", - fields: [ - { - customId: "reason", - label: "Who are you reporting and why?", - style: "PARAGRAPH", - placeholder: "Provide details about the user you are reporting", - required: true, - maxLength: 1024, - }, - ], - }, - { - label: "βš’οΈ Apply For Staff", - value: "staff", - fields: [ - { - customId: "reason", - label: "Why do you want to join the staff team?", - style: "PARAGRAPH", - placeholder: "Explain why you want to join the staff team", - required: true, - maxLength: 1024, - }, - { - customId: "experience", - label: "Do you have any prior moderation experience?", - style: "PARAGRAPH", - placeholder: "Describe any prior moderation experience you have", - required: false, - maxLength: 1024, - }, - ], - }, - { - label: "πŸ“ Other", - value: "other", - fields: [ - { - customId: "reason", - label: "Reason", - style: "PARAGRAPH", - placeholder: "Explain why you are opening this ticket", - required: true, - maxLength: 1024, - }, - ], - }, - { - label: "🀝 Partnership", - value: "partnership", - fields: [ - { - customId: "about", - label: "What is your server about?", - style: "PARAGRAPH", - placeholder: "Provide details about your community", - required: true, - maxLength: 1024, - }, - ], - }, -]; - -function getSelectedOption(ticketType) { - return selectMenu.find((option) => option.value === ticketType); -} - -export default { - id: "ticket_type_select", - callback: async (client, interaction) => { - if (interaction.user.bot) return; - - const ticketType = interaction.values[0]; - const selectedOption = getSelectedOption(ticketType); - const ticketLabel = ticketType; - const id = crypto.randomBytes(4).toString("hex"); - - const modalId = `ticket_modal_${interaction.user.id}_${Date.now()}`; - const modal = buildModal(client, { - customId: modalId, - title: "Open a Ticket", - fields: selectedOption - ? selectedOption.fields - : [ - { - customId: "reason", - label: "Reason", - style: "PARAGRAPH", - placeholder: - "Explain why you are opening this ticket (max 1024 chars)", - required: true, - maxLength: 1024, - }, - ], - }); - - try { - await interaction.showModal(modal); - } catch (err) { - console.error("Failed to show modal:", err); - await interaction.reply({ - content: "Something went wrong showing the form. Please try again.", - ephemeral: true, - }); - return; - } - - let modalSubmit; - try { - modalSubmit = await interaction.awaitModalSubmit({ - filter: (i) => - i.user.id === interaction.user.id && i.customId === modalId, - time: 300000, - }); - } catch (e) { - console.error("Modal submit error or timeout:", e); - await interaction.followUp({ - content: "You did not submit the ticket form in time.", - ephemeral: true, - }); - return; - } - - await modalSubmit.deferReply({ ephemeral: true }); - - const safeName = `${ticketLabel}-${id}`; - - const overwrites = [ - { - id: interaction.guild.roles.everyone.id, - deny: [PermissionFlagsBits.ViewChannel], - }, - { - id: interaction.user.id, - allow: [ - PermissionFlagsBits.ViewChannel, - PermissionFlagsBits.SendMessages, - PermissionFlagsBits.ReadMessageHistory, - ], - }, - ]; - - if (serverConfig.moderatorRoleId) { - overwrites.push({ - id: serverConfig.moderatorRoleId, - allow: [ - PermissionFlagsBits.ViewChannel, - PermissionFlagsBits.SendMessages, - PermissionFlagsBits.ManageMessages, - PermissionFlagsBits.ReadMessageHistory, - ], - }); - } - - let ticketChannel; - try { - ticketChannel = await interaction.guild.channels.create({ - name: safeName, - type: ChannelType.GuildText, - parent: serverConfig.tickets.category ?? undefined, - topic: ticketLabel, - permissionOverwrites: overwrites, - }); - } catch (err) { - console.error("Failed creating ticket channel:", err); - await modalSubmit.reply({ - content: "Failed to create ticket channel. Please contact an admin.", - ephemeral: true, - }); - return; - } - - const ticketEmbed = new EmbedBuilder() - .setTitle("Ticket Created") - .addFields( - { - name: "By", - value: interaction.user.toString(), - inline: true, - }, - { - name: "Type", - value: selectedOption?.label ?? ticketType, - inline: true, - }, - { - name: "Created At", - value: ``, - inline: true, - }, - ...(selectedOption?.fields || []).map((field) => ({ - name: field.label, - value: modalSubmit.fields.getTextInputValue(field.customId) || "N/A", - inline: false, - })), - ) - .setFooter({ - text: `${interaction.user.id}`, - iconURL: interaction.user.displayAvatarURL(), - }); - - const closeButton = new ButtonBuilder() - .setCustomId("close_ticket") - .setLabel("Close Ticket") - .setStyle(ButtonStyle.Danger); - const actionRow = new ActionRowBuilder().addComponents(closeButton); - - const posted = await ticketChannel.send({ - content: `${interaction.user} <@&${serverConfig.tickets.ticketsAdminId}>`, - embeds: [ticketEmbed], - components: [actionRow], - }); - try { - await posted.pin(); - } catch (e) { - // ignore - } - - await modalSubmit.editReply({ - content: `Ticket created: ${ticketChannel}`, - }); - }, -}; diff --git a/src/interactions/ticketButton.ts b/src/interactions/ticketButton.ts new file mode 100644 index 0000000..5e5134d --- /dev/null +++ b/src/interactions/ticketButton.ts @@ -0,0 +1,60 @@ +import { + InteractionHandler, + InteractionHandlerTypes, +} from "@sapphire/framework"; +import { + ChannelType, + MessageFlags, + ModalBuilder, + TextInputBuilder, + TextInputStyle, + type ButtonInteraction, +} from "discord.js"; +import { config } from "../config/app.ts"; +import { interactionKeys } from "../constants/interactions.ts"; + +export class TicketButton extends InteractionHandler { + public constructor(context: InteractionHandler.LoaderContext) { + super(context, { + interactionHandlerType: InteractionHandlerTypes.Button, + enabled: config.modules.tickets.enabled, + }); + } + + public async run(interaction: ButtonInteraction) { + const category = await interaction.guild?.channels.fetch( + config.modules.tickets.category, + ); + + if ( + category && + interaction.guild && + category.type === ChannelType.GuildCategory + ) { + const input = new TextInputBuilder() + .setCustomId(interactionKeys.ticketReason) + .setLabel("What can we help you with?") + .setStyle(TextInputStyle.Paragraph) + .setRequired(true); + + const modal = new ModalBuilder() + .setCustomId(interactionKeys.ticketOpen) + .setTitle("Thank you for opening this ticket!") + .addComponents(input); + + interaction.showModal(modal); + } else { + return await interaction.reply({ + content: "Ticket setup not complete yet. Try again later.", + flags: MessageFlags.Ephemeral, + }); + } + } + + public parse(interaction: ButtonInteraction) { + if (!interaction.customId.startsWith(interactionKeys.ticketButton)) + return this.none(); + + return this.some(); + } +} diff --git a/src/interactions/ticketClose.ts b/src/interactions/ticketClose.ts new file mode 100644 index 0000000..3396d08 --- /dev/null +++ b/src/interactions/ticketClose.ts @@ -0,0 +1,104 @@ +import { + InteractionHandler, + InteractionHandlerTypes, +} from "@sapphire/framework"; +import { + AttachmentBuilder, + ChannelType, + EmbedBuilder, + MessageFlags, + type ButtonInteraction, +} from "discord.js"; +import { config } from "../config/app.ts"; +import { interactionKeys } from "../constants/interactions.ts"; +import { client } from "../index.ts"; +import { buildTranscripts } from "../lib/transcripts.ts"; + +export class TicketClose extends InteractionHandler { + public constructor(context: InteractionHandler.LoaderContext) { + super(context, { + interactionHandlerType: InteractionHandlerTypes.Button, + enabled: config.modules.tickets.enabled, + }); + } + + public async run(interaction: ButtonInteraction) { + const category = await interaction.guild?.channels.fetch( + config.modules.tickets.category, + ); + + if ( + category && + interaction.guild && + category.type === ChannelType.GuildCategory + ) { + const embed = interaction.message.embeds[0]; + // const transcript = ( + // await interaction.channel?.messages.fetch({ limit: 100 }) + // ) + // ?.filter((msg) => !msg.author.bot) + // .map( + // (msg) => + // `(${new Date(msg.createdTimestamp).toLocaleString()}) [${msg.author.tag}] ${msg.content}`, + // ) + // .reverse() + // .join("\n\n"); + const messages = await interaction.channel?.messages.fetch({ + limit: 100, + }); + const transcriptsChannel = await interaction.guild.channels.fetch( + config.modules.tickets.transcripts, + ); + let transcript; + + if (messages) + transcript = await buildTranscripts( + client, + [...messages.values()].reverse(), + ); + + await interaction.channel?.delete(); + + let user; + + if (embed) { + const embedLog = EmbedBuilder.from(embed).setTitle("Ticket Closed"); + + const attachment = transcript + ? new AttachmentBuilder(Buffer.from(transcript), { + name: "transcript.html", + }) + : null; + + if (embed.footer) { + user = await client.users.fetch(embed.footer.text); + + await user.send({ + embeds: [embedLog.setThumbnail(interaction.guild.iconURL())], + files: attachment ? [attachment] : [], + }); + } + + if (transcriptsChannel?.isSendable()) + await transcriptsChannel.send({ + embeds: user + ? [embedLog.setThumbnail(user.displayAvatarURL())] + : [], + files: attachment ? [attachment] : [], + }); + } + } else { + return await interaction.reply({ + content: "This interaction is only allowed in ticket channels.", + flags: MessageFlags.Ephemeral, + }); + } + } + + public parse(interaction: ButtonInteraction) { + if (!interaction.customId.startsWith(interactionKeys.ticketClose)) + return this.none(); + + return this.some(); + } +} diff --git a/src/interactions/ticketOpen.ts b/src/interactions/ticketOpen.ts new file mode 100644 index 0000000..48ca02d --- /dev/null +++ b/src/interactions/ticketOpen.ts @@ -0,0 +1,123 @@ +import { + InteractionHandler, + InteractionHandlerTypes, +} from "@sapphire/framework"; +import type { ModalSubmitInteraction } from "discord.js"; +import { + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + ChannelType, + EmbedBuilder, + MessageFlags, + PermissionFlagsBits, + type ButtonInteraction, +} from "discord.js"; +import { config } from "../config/app.ts"; +import { colors } from "../constants/colors.ts"; +import { interactionKeys } from "../constants/interactions.ts"; +import { generateId } from "../lib/id.ts"; + +export class TicketOpen extends InteractionHandler { + public constructor(context: InteractionHandler.LoaderContext) { + super(context, { + interactionHandlerType: InteractionHandlerTypes.ModalSubmit, + enabled: config.modules.tickets.enabled, + }); + } + + public async run(interaction: ModalSubmitInteraction) { + const category = await interaction.guild?.channels.fetch( + config.modules.tickets.category, + ); + + if ( + category && + interaction.guild && + category.type === ChannelType.GuildCategory + ) { + const reason = interaction.fields.getTextInputValue( + interactionKeys.ticketReason, + ); + const id = generateId(); + const name = `ticket-${id}`; + + const ticket = await category.children.create({ + name, + type: ChannelType.GuildText, + permissionOverwrites: [ + { + id: interaction.guild.roles.everyone.id, + deny: [PermissionFlagsBits.ViewChannel], + }, + { + id: interaction.user.id, + allow: [PermissionFlagsBits.ViewChannel], + }, + ...config.modules.tickets.mods.map((mod) => ({ + id: mod, + allow: [PermissionFlagsBits.ViewChannel], + })), + ], + }); + + const embed = new EmbedBuilder() + .setTitle(`Ticket by ${interaction.user.tag}`) + .addFields([ + { + name: "By", + value: interaction.user.toString(), + inline: true, + }, + { + name: "ID", + value: id, + inline: true, + }, + { + name: "Date", + value: ``, + inline: true, + }, + { + name: "Reason", + value: reason, + }, + ]) + .setColor(colors.primary) + .setFooter({ text: interaction.user.id }) + .setThumbnail(interaction.user.displayAvatarURL()); + + const row = new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setCustomId(interactionKeys.ticketClose) + .setLabel("Close ticket") + .setStyle(ButtonStyle.Danger), + ); + + const ticketMessage = await ticket.send({ + content: `${interaction.user} ${config.modules.tickets.mention.map((m) => `<@&${m}>`).join(" ")}`, + embeds: [embed], + components: [row], + }); + await ticketMessage.pin(); + + await interaction.reply({ + content: `Ticket created: ${ticket}`, + flags: MessageFlags.Ephemeral, + }); + } else { + return await interaction.reply({ + content: "Something went wrong. Please try again later.", + flags: MessageFlags.Ephemeral, + }); + } + } + + public parse(interaction: ButtonInteraction) { + if (!interaction.customId.startsWith(interactionKeys.ticketOpen)) + return this.none(); + + return this.some(); + } +} diff --git a/src/lib/id.ts b/src/lib/id.ts new file mode 100644 index 0000000..1da9334 --- /dev/null +++ b/src/lib/id.ts @@ -0,0 +1,7 @@ +import { randomBytes } from "crypto"; + +export function generateId(length: number = 8) { + return randomBytes(Math.ceil(length / 2)) + .toString("hex") + .slice(0, length); +} diff --git a/src/lib/logger.ts b/src/lib/logger.ts new file mode 100644 index 0000000..c81a2de --- /dev/null +++ b/src/lib/logger.ts @@ -0,0 +1,36 @@ +import pc from "picocolors"; + +const prefix = pc.bold(pc.magenta("bot")); + +export const logger = { + info(msg: string) { + console.log(`${prefix} ${pc.cyan("β€Ί")} ${msg}`); + }, + + success(msg: string) { + console.log(`${prefix} ${pc.green("βœ“")} ${msg}`); + }, + + warn(msg: string) { + console.warn(`${prefix} ${pc.yellow("⚠")} ${pc.yellow(msg)}`); + }, + + error(msg: string, err?: Error | string | unknown) { + console.error(`${prefix} ${pc.red("βœ—")} ${pc.red(msg)}`); + + if (err) { + console.log("\n"); + console.error(err instanceof Error ? err.message : String(err)); + } + }, + + debug(msg: string) { + if (process.env.DISPOD_DEBUG) { + console.log(`${prefix} ${pc.gray("Β·")} ${pc.gray(msg)}`); + } + }, + + br() { + console.log(); + }, +}; diff --git a/src/utils/buildTicketTranscript.js b/src/lib/transcripts.ts similarity index 87% rename from src/utils/buildTicketTranscript.js rename to src/lib/transcripts.ts index 1dca929..fb39d2f 100644 --- a/src/utils/buildTicketTranscript.js +++ b/src/lib/transcripts.ts @@ -1,4 +1,6 @@ -const escapeHtml = (text) => { +import type { Client, Message } from "discord.js"; + +const escapeHtml = (text: string) => { return text .replace(/&/g, "&") .replace(/ { .replace(/'/g, "'"); }; -export default async (client, messages) => { +export async function buildTranscripts(client: Client, messages: Message[]) { let html = ` @@ -21,68 +23,55 @@ export default async (client, messages) => { font-family: "gg sans", "Segoe UI", Helvetica, Arial, sans-serif; color: #dbdee1; } - .chat { max-width: 900px; padding: 20px; } - .message-group { display: flex; padding: 3px 5px; } - .message-group:has(.avatar) .message-content .header { padding-bottom: 5px; } - .message-group:has(.avatar):not(:first-child) { margin-top: 12px; } - .message-group:hover { background-color: rgba(255, 255, 255, 0.04); } - .avatar { width: 40px; height: 40px; border-radius: 50%; margin-right: 16px; } - .message-content { flex: 1; } - .header { display: flex; align-items: center; gap: 6px; } - .username { font-weight: 500; font-size: 16px; color: #f2f3f5; } - .timestamp { font-size: 12px; color: #949ba4; } - .message { font-size: 15px; line-height: 1.375rem; white-space: pre-wrap; word-wrap: break-word; } - .message-wrapper { border-radius: 4px; } - .reply { display: flex; align-items: center; @@ -90,18 +79,15 @@ export default async (client, messages) => { color: #b5bac1; margin-bottom: 4px; } - .reply-line { width: 20px; height: 1px; background: #4f545c; margin-right: 6px; } - .reply span { opacity: 0.8; } - .attachment img { max-width: 350px; border-radius: 8px; @@ -116,18 +102,21 @@ export default async (client, messages) => { for (const msg of messages) { try { - const user = await client.users.fetch(msg.authorId); + const user = await client.users.fetch(msg.author.id); const avatar = user.displayAvatarURL({ size: 64 }); - const time = new Date(msg.timestamp).toLocaleString(); + const time = new Date(msg.createdTimestamp).toLocaleString(); + const sameAuthor = lastAuthor === msg.author.id; - const sameAuthor = lastAuthor === msg.authorId; - lastAuthor = msg.authorId; + lastAuthor = msg.author.id; let replyHtml = ""; + if (msg.reference?.messageId) { - const ref = messages.find((m) => m.id === msg.reference.messageId); + const ref = messages.find((m) => m.id === msg.id); + if (ref) { - const refUser = await client.users.fetch(ref.authorId); + const refUser = await client.users.fetch(ref.author.id); + replyHtml = `
@@ -189,4 +178,4 @@ export default async (client, messages) => { `; return html; -}; +} diff --git a/src/listeners/afk/afk.ts b/src/listeners/afk/afk.ts new file mode 100644 index 0000000..905e3a8 --- /dev/null +++ b/src/listeners/afk/afk.ts @@ -0,0 +1,57 @@ +import { Listener } from "@sapphire/framework"; +import type { Message } from "discord.js"; +import { EmbedBuilder, Events } from "discord.js"; +import { open } from "lmdb"; +import path from "path"; +import { config } from "../../config/app.ts"; +import { colors } from "../../constants/colors.ts"; +import { dbkeys, dbPath } from "../../constants/db.ts"; +import type { AFKDB } from "../../types/afk.ts"; + +const db = open(path.join(dbPath, dbkeys.afk), { + compression: true, +}); + +export class AFK extends Listener { + public constructor( + context: Listener.LoaderContext, + options: Listener.Options, + ) { + super(context, { + ...options, + event: Events.MessageCreate, + enabled: config.modules.afk.enabled, + }); + } + + public async run(message: Message) { + if (message.author.bot) return; + + const mentioned = message.mentions.users.first(); + + if (!mentioned) return; + + const entry = db.get(mentioned.id); + + if (!entry) return; + + const embed = new EmbedBuilder() + .setDescription( + `${mentioned} is currently AFK${entry.reason ? `: ${entry.reason}` : ""}`, + ) + .setAuthor({ + name: mentioned.displayName, + iconURL: mentioned.displayAvatarURL(), + }) + .setColor(colors.primary); + + db.put(mentioned.id, { + ...entry, + mentions: (entry.mentions ?? 0) + 1, + }); + + const msg = await message.reply({ embeds: [embed] }); + + setTimeout(async () => await msg.delete(), 15_000); + } +} diff --git a/src/listeners/afk/back.ts b/src/listeners/afk/back.ts new file mode 100644 index 0000000..4521708 --- /dev/null +++ b/src/listeners/afk/back.ts @@ -0,0 +1,53 @@ +import { Listener } from "@sapphire/framework"; +import type { Message } from "discord.js"; +import { EmbedBuilder, Events } from "discord.js"; +import { open } from "lmdb"; +import path from "path"; +import { config } from "../../config/app.ts"; +import { colors } from "../../constants/colors.ts"; +import { dbkeys, dbPath } from "../../constants/db.ts"; +import type { AFKDB } from "../../types/afk.ts"; + +const db = open(path.join(dbPath, dbkeys.afk), { + compression: true, +}); + +export class AFKBack extends Listener { + public constructor( + context: Listener.LoaderContext, + options: Listener.Options, + ) { + super(context, { + ...options, + event: Events.MessageCreate, + enabled: config.modules.afk.enabled, + }); + } + + public async run(message: Message) { + if (message.author.bot) return; + + const entry = db.get(message.author.id); + + if (!entry) return; + + const embed = new EmbedBuilder() + .setDescription( + `Welcome back, ${message.author}! Your AFK status has been removed.`, + ) + .setAuthor({ + name: message.author.displayName, + iconURL: message.author.displayAvatarURL(), + }) + .setFooter({ + text: `recieved ${entry.mentions ?? 0} mentions while AFK`, + }) + .setColor(colors.success); + + db.remove(message.author.id); + + const msg = await message.reply({ embeds: [embed] }); + + setTimeout(async () => await msg.delete(), 15_000); + } +} diff --git a/src/listeners/counting/countdelete.ts b/src/listeners/counting/countdelete.ts new file mode 100644 index 0000000..139564a --- /dev/null +++ b/src/listeners/counting/countdelete.ts @@ -0,0 +1,49 @@ +import { Events, Listener } from "@sapphire/framework"; +import type { Message } from "discord.js"; +import { open } from "lmdb"; +import path from "path"; +import { config } from "../../config/app.ts"; +import { dbkeys, dbPath } from "../../constants/db.ts"; +import type { CountDB } from "../../types/counting.ts"; + +const db = open(path.join(dbPath, dbkeys.counting), {}); + +export class CountMessageDelete extends Listener { + public constructor( + context: Listener.LoaderContext, + options: Listener.Options, + ) { + super(context, { + ...options, + event: Events.MessageDelete, + enabled: config.modules.counting.enabled, + }); + } + + public async run(message: Message) { + if ( + message.author.bot || + message.channelId !== config.modules.counting.channel + ) + return; + + const count = Number(message.content.split(" ")[0]); + + if (isNaN(count)) return; + + const data = db.get(dbkeys.counting) ?? { + lastUser: "", + lastCount: 0, + saves: 0, + }; + + const { lastUser, lastCount } = data; + + if (count !== lastCount || message.author.id !== lastUser) return; + + if (message.channel.isSendable()) + await message.channel.send( + `${message.author} just deleted their count, the next count is still ${lastCount + 1}`, + ); + } +} diff --git a/src/listeners/counting/counting.ts b/src/listeners/counting/counting.ts new file mode 100644 index 0000000..923d0a9 --- /dev/null +++ b/src/listeners/counting/counting.ts @@ -0,0 +1,109 @@ +import { Events, Listener } from "@sapphire/framework"; +import type { Message } from "discord.js"; +import { open } from "lmdb"; +import path from "path"; +import { config } from "../../config/app.ts"; +import { dbkeys, dbPath } from "../../constants/db.ts"; +import type { CountDB } from "../../types/counting.ts"; + +const db = open(path.join(dbPath, dbkeys.counting), {}); + +export class Counting extends Listener { + public constructor( + context: Listener.LoaderContext, + options: Listener.Options, + ) { + super(context, { + ...options, + event: Events.MessageCreate, + enabled: config.modules.counting.enabled, + }); + } + + async run(message: Message) { + if ( + message.channelId !== config.modules.counting.channel || + message.author.bot + ) + return; + + const count = Number(message.content.split(" ")[0]); + + if (isNaN(count)) return; + + const data = db.get(dbkeys.counting) ?? { + lastUser: "", + lastCount: 0, + saves: 0, + }; + + const { lastUser, lastCount, saves } = data; + + if (lastUser && message.author.id === lastUser) { + return await message.react("⁉️"); + } + + if (count !== lastCount + 1) { + if (lastCount === 0) { + await message.react("🫩"); + + return message.channel.isSendable() + ? await message.channel.send( + `${message.author}, the count has been reset, the next count is 0.`, + ) + : undefined; + } + + if (saves > 0) { + db.put(dbkeys.counting, { lastUser, lastCount, saves: saves - 1 }); + + await message.react("❌"); + + return message.channel.isSendable() + ? await message.channel.send( + `${message.author} burned a save by ruining the count at ${count}! You have ${saves - 1} saves left. The next count is ${lastCount + 1}`, + ) + : undefined; + } + + db.put(dbkeys.counting, { lastUser: "", lastCount: 0, saves: 0 }); + + return message.channel.isSendable() + ? await message.channel.send( + `${message.author} ruined the count at ${count}! Count has been reset, the next number is 1.`, + ) + : undefined; + } + + let updatedSaves = saves; + + // rewards (+saves) + if (count === 100) { + const savesToAdd = 3; + + updatedSaves += savesToAdd; + + if (message.channel.isSendable()) + await message.channel.send( + `We've reached ${count} counts!! ${savesToAdd} saves has been added! Keep it up ⚑`, + ); + } else if (count % 500 === 0) { + const savesToAdd = Math.min(count / 250, 10); + + updatedSaves += savesToAdd; + + if (message.channel.isSendable()) + await message.channel.send( + `We've reached ${count} counts!! +${savesToAdd} saves has been added! Keep it up ⚑`, + ); + } + + db.put(dbkeys.counting, { + lastUser: message.author.id, + lastCount: count, + saves: updatedSaves, + }); + + await message.react("βœ…"); + } +} diff --git a/src/listeners/macros/macros.ts b/src/listeners/macros/macros.ts new file mode 100644 index 0000000..73d5034 --- /dev/null +++ b/src/listeners/macros/macros.ts @@ -0,0 +1,39 @@ +import { Listener } from "@sapphire/framework"; +import type { Message } from "discord.js"; +import { Events } from "discord.js"; +import { config } from "../../config/app.ts"; +import macros from "../../data/macros.json" with { type: "json" }; + +export class Macros extends Listener { + constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { + ...options, + event: Events.MessageCreate, + enabled: config.modules.macros.enabled, + }); + } + + public async run(message: Message) { + if (message.author.bot) return; + + const prefix = config.settings.prefixes.macros.find((p) => + message.content.startsWith(p), + ); + + if (!prefix) return; + + const macroText = message.content.split(prefix)[1]?.split(" ")[0]; + + if (!macroText) return; + + const macro = macros.find( + (m) => m.c === macroText || m.a?.includes(macroText), + ); + + if (!macro) return; + + if (config.modules.macros.deleteOG) await message.delete(); + + if (message.channel.isSendable()) await message.channel.send(macro.r); + } +} diff --git a/src/listeners/macros/rules.ts b/src/listeners/macros/rules.ts new file mode 100644 index 0000000..1fdea32 --- /dev/null +++ b/src/listeners/macros/rules.ts @@ -0,0 +1,45 @@ +import { Listener } from "@sapphire/framework"; +import type { Message } from "discord.js"; +import { EmbedBuilder, Events } from "discord.js"; +import { config } from "../../config/app.ts"; +import { colors } from "../../constants/colors.ts"; +import rules from "../../data/rules.json" with { type: "json" }; + +export class Rules extends Listener { + constructor(context: Listener.LoaderContext, options: Listener.Options) { + super(context, { + ...options, + event: Events.MessageCreate, + enabled: config.modules.macros.enabled, + }); + } + + public async run(message: Message) { + if (message.author.bot) return; + + const prefix = config.settings.prefixes.macros.find((p) => + message.content.startsWith(p), + ); + + if (!prefix) return; + + const ruleNumber = message.content.split(prefix)[1]?.split(" ")[0]; + + if (!ruleNumber) return; + + const rule = rules.find((r) => r.c === ruleNumber); + + if (!rule) return; + + if (config.modules.macros.deleteOG) await message.delete(); + + const embed = new EmbedBuilder() + .setTitle(rule.t) + .setDescription(rule.pts.map((pt) => `- ${pt}`).join("\n")) + .setColor(colors.primary) + .setThumbnail(message.guild?.iconURL() ?? null); + + if (message.channel.isSendable()) + await message.channel.send({ embeds: [embed] }); + } +} diff --git a/src/listeners/misc/easterEggs.ts b/src/listeners/misc/easterEggs.ts new file mode 100644 index 0000000..43741aa --- /dev/null +++ b/src/listeners/misc/easterEggs.ts @@ -0,0 +1,57 @@ +import { Listener } from "@sapphire/framework"; +import type { Message } from "discord.js"; +import { Events } from "discord.js"; +import { config } from "../../config/app.ts"; +import { client } from "../../index.ts"; + +export class EasterEggs extends Listener { + public constructor( + context: Listener.LoaderContext, + options: Listener.Options, + ) { + super(context, { + ...options, + event: Events.MessageCreate, + enabled: config.modules.easterEggs.enabled, + }); + } + + public async run(message: Message) { + if (message.author.bot) return; + + const random = Math.random(); + + if (message.mentions.users?.has(client.id || "")) { + const gifs = [ + "https://klipy.com/gifs/who-pinged-me-ping", + "https://klipy.com/gifs/who-the-5", + "https://klipy.com/gifs/slumber-disturb-1", + ]; + + const gif = gifs[Math.floor(Math.random() * gifs.length)]; + + const chance = random < 0.05; + + if (chance && gif && message.channel.isSendable()) + await message.channel.send(gif); + } + + switch (message.content) { + case "aww": + case "❀️": + if (random < 0.1) await message.react("❀️"); + break; + + case "bruh": + case "lol": + case "lmao": + case "seriously": + if (random < 0.2) await message.react("πŸ˜‚"); + break; + + default: + if (random < 0.01) await message.react("πŸ‘€"); + break; + } + } +} diff --git a/src/listeners/misc/starboard.ts b/src/listeners/misc/starboard.ts new file mode 100644 index 0000000..fa08f0d --- /dev/null +++ b/src/listeners/misc/starboard.ts @@ -0,0 +1,100 @@ +import { Listener } from "@sapphire/framework"; +import type { MessageReaction, PartialMessageReaction } from "discord.js"; +import { + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + EmbedBuilder, + Events, +} from "discord.js"; +import { config } from "../../config/app.ts"; +import { colors } from "../../constants/colors.ts"; + +export class Starboard extends Listener { + public constructor( + context: Listener.LoaderContext, + options: Listener.Options, + ) { + super(context, { + ...options, + event: Events.MessageReactionAdd, + enabled: config.modules.starboard.enabled, + }); + } + + public async run(reaction: MessageReaction | PartialMessageReaction) { + if (reaction.message.partial) await reaction.message.fetch(); + if (reaction.partial) await reaction.fetch(); + + if (!reaction.message.author) return; + + if ( + // ignore reactions in starboard channel itself + reaction.message.channelId === config.modules.starboard.channel || + // starboard excluded channels + (config.modules.starboard.exclude.channels as string[]).includes( + reaction.message.channelId, + ) || + // starboard excluded categories + ("parentId" in reaction.message.channel && + // reaction.message.channel.parentId && + (config.modules.starboard.exclude.categories as string[]).includes( + reaction.message.channel.parentId as string, + )) + ) + return; + + const reactions = reaction.message.reactions.cache.filter( + (r) => + config.modules.starboard.emojis.includes(r.emoji.name ?? "") && + r.count >= config.modules.starboard.reactionsRequired, + ); + + if (reactions.size === 0) return; + + const topReaction = reactions + .reduce((max, r) => (r.count > max.count ? r : max), reactions.first()) + .emoji.toString(); + + const starboardChannel = await reaction.message.guild?.channels.fetch( + config.modules.starboard.channel, + ); + + if (!starboardChannel || !starboardChannel.isTextBased()) return; + + const exists = (await starboardChannel.messages.fetch({ limit: 50 })).find( + (msg) => msg.embeds[0]?.footer?.text.includes(reaction.message.id), + ); + + if (exists) return; + + const embed = new EmbedBuilder() + .setAuthor({ + name: reaction.message.author.tag, + iconURL: reaction.message.author.displayAvatarURL(), + }) + .setFooter({ text: reaction.message.id }) + .setColor(colors.primary); + + if (reaction.message.content) + embed.setDescription(`>>> ${reaction.message.content}`); + + const attachment = reaction.message.attachments.first(); + if (attachment?.contentType?.startsWith("image/")) + embed.setImage(attachment.url); + + const row = new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setLabel("Jump to Message") + .setStyle(ButtonStyle.Link) + .setURL(reaction.message.url), + ); + + const msg = await starboardChannel.send({ + embeds: [embed], + components: [row], + }); + + await msg.react(topReaction); + } +} diff --git a/src/listeners/misc/stickyMessages.ts b/src/listeners/misc/stickyMessages.ts new file mode 100644 index 0000000..557f21a --- /dev/null +++ b/src/listeners/misc/stickyMessages.ts @@ -0,0 +1,44 @@ +import { Listener } from "@sapphire/framework"; +import type { Message } from "discord.js"; +import { Events } from "discord.js"; +import { config } from "../../config/app.ts"; +import { client } from "../../index.ts"; + +export class StickyMessages extends Listener { + public constructor( + context: Listener.LoaderContext, + options: Listener.Options, + ) { + super(context, { + ...options, + event: Events.MessageCreate, + enabled: config.modules.stickyMessages.enabled, + }); + } + + public async run(message: Message) { + if (message.author.bot) return; + + const stickyMessages = config.modules.stickyMessages.messages as Record< + string, + { content: string; react?: string[] } + >; + + const stickyMessage = stickyMessages[message.channelId]; + + if (!stickyMessage) return; + + (await message.channel.messages.fetch({ limit: 15 })) + .find( + (msg) => + msg.author.id === client.id && msg.content === stickyMessage.content, + ) + ?.delete(); + + if (message.channel.isSendable()) + await message.channel.send(stickyMessage.content); + + if (stickyMessage.react) + stickyMessage.react.forEach(async (emoji) => await message.react(emoji)); + } +} diff --git a/src/listeners/system/dbCleanup.ts b/src/listeners/system/dbCleanup.ts new file mode 100644 index 0000000..58e192f --- /dev/null +++ b/src/listeners/system/dbCleanup.ts @@ -0,0 +1,29 @@ +import { Listener } from "@sapphire/framework"; +import type { GuildMember } from "discord.js"; +import { Events } from "discord.js"; +import { open } from "lmdb"; +import path from "path"; +import { dbkeys, dbPath } from "../../constants/db.ts"; +import type { AFKDB } from "../../types/afk.ts"; + +const afkDB = open(path.join(dbPath, dbkeys.afk), { + compression: true, +}); + +export class DBCleanup extends Listener { + public constructor( + context: Listener.LoaderContext, + options: Listener.Options, + ) { + super(context, { + ...options, + event: Events.GuildMemberRemove, + }); + } + + public run(member: GuildMember) { + if (member.user.bot) return; + + afkDB.remove(member.user.id); + } +} diff --git a/src/listeners/system/ready.ts b/src/listeners/system/ready.ts new file mode 100644 index 0000000..f126fb3 --- /dev/null +++ b/src/listeners/system/ready.ts @@ -0,0 +1,45 @@ +import { Listener } from "@sapphire/framework"; +import type { Client } from "discord.js"; +import { ActivityType, Events, PresenceUpdateStatus } from "discord.js"; +import { logger } from "../../lib/logger.ts"; + +export class Ready extends Listener { + public presenceInterval: NodeJS.Timeout | undefined; + + public constructor( + context: Listener.LoaderContext, + options: Listener.Options, + ) { + super(context, { + ...options, + // once: true, + event: Events.ClientReady, + }); + } + + private setPresence(client: Client) { + const update = () => { + client.user?.setPresence({ + activities: [ + { + name: "too lazy to load commands...", + type: ActivityType.Listening, + }, + ], + status: PresenceUpdateStatus.DoNotDisturb, + }); + }; + + update(); + + if (this.presenceInterval) clearInterval(this.presenceInterval); + + this.presenceInterval = setInterval(update, 60 * 60 * 1000); + } + + public run(client: Client) { + logger.info(`Logged in as '${client.user?.username}'`); + + this.setPresence(client); + } +} diff --git a/src/listeners/welcome/dm.ts b/src/listeners/welcome/dm.ts new file mode 100644 index 0000000..51284bf --- /dev/null +++ b/src/listeners/welcome/dm.ts @@ -0,0 +1,37 @@ +import { Listener } from "@sapphire/framework"; +import type { GuildMember } from "discord.js"; +import { EmbedBuilder, Events } from "discord.js"; +import { config } from "../../config/app.ts"; +import { colors } from "../../constants/colors.ts"; + +export class WelcomeDM extends Listener { + public constructor( + context: Listener.LoaderContext, + options: Listener.Options, + ) { + super(context, { + ...options, + event: Events.GuildMemberAdd, + enabled: config.modules.welcome.dm, + }); + } + + public async run(member: GuildMember) { + if (member.user.bot) return; + + const embed = new EmbedBuilder() + .setTitle(`Welcome ${member.user.tag} to ${member.guild.name}!`) + .setDescription( + [ + `Welcome ${member}, We're delighted to have you join us in ${member.guild.name}!`, + `Take a moment to explore the channels, introduce yourself, and connect with the community.`, + `Once again, a warm welcome aboard, we look forward to your contributions and conversations! 🌟`, + ].join("\n"), + ) + .setThumbnail(member.guild.iconURL()) + .setColor(colors.primary) + .setTimestamp(); + + await member.send({ embeds: [embed] }); + } +} diff --git a/src/listeners/welcome/welcome.ts b/src/listeners/welcome/welcome.ts new file mode 100644 index 0000000..cfe6a26 --- /dev/null +++ b/src/listeners/welcome/welcome.ts @@ -0,0 +1,39 @@ +import { Listener } from "@sapphire/framework"; +import type { GuildMember } from "discord.js"; +import { EmbedBuilder, Events } from "discord.js"; +import { config } from "../../config/app.ts"; +import { colors } from "../../constants/colors.ts"; + +export class Welcome extends Listener { + public constructor( + context: Listener.LoaderContext, + options: Listener.Options, + ) { + super(context, { + ...options, + event: Events.GuildMemberAdd, + enabled: config.modules.welcome.enabled, + }); + } + + public async run(member: GuildMember) { + const channel = + (await member.guild.channels.fetch(config.modules.welcome.channel)) ?? + member.guild.systemChannel; + + const embed = new EmbedBuilder() + .setTitle(`Welcome ${member.user.tag} to ${member.guild.name}!`) + .setDescription( + [ + `Welcome ${member}, We're delighted to have you join us in ${member.guild.name}!`, + `Take a moment to explore the channels, introduce yourself, and connect with the community.`, + `Once again, a warm welcome aboard, we look forward to your contributions and conversations! 🌟`, + ].join("\n"), + ) + .setThumbnail(member.displayAvatarURL()) + .setColor(colors.primary) + .setTimestamp(); + + if (channel?.isSendable()) await channel.send({ embeds: [embed] }); + } +} diff --git a/src/models/Counting.js b/src/models/Counting.js deleted file mode 100644 index 196214f..0000000 --- a/src/models/Counting.js +++ /dev/null @@ -1,16 +0,0 @@ -import mongoose from "mongoose"; - -const countingSchema = new mongoose.Schema({ - userId: { - type: String, - required: true, - unique: true, - }, - counts: { - type: Number, - default: 0, - required: true, - }, -}); - -export default mongoose.model("Counting", countingSchema); diff --git a/src/models/Profile.js b/src/models/Profile.js deleted file mode 100644 index 67adf06..0000000 --- a/src/models/Profile.js +++ /dev/null @@ -1,51 +0,0 @@ -import mongoose from "mongoose"; - -const profileSchema = new mongoose.Schema({ - userId: { - type: String, - required: true, - unique: true, - }, - - bio: { - type: String, - default: "", - maxLength: 200, - }, - - country: { - type: String, - default: "", - maxLength: 50, - }, - - age: { - type: Number, - min: -1000, - max: 1000, - }, - - stack: { - type: String, - default: "", - maxLength: 100, - }, - - github: { - type: String, - default: "", - }, - - portfolio: { - type: String, - default: "", - }, - - hobbies: { - type: String, - default: "", - maxLength: 200, - }, -}); - -export default mongoose.model("Profile", profileSchema); diff --git a/src/models/SuspendedMember.js b/src/models/SuspendedMember.js deleted file mode 100644 index c733464..0000000 --- a/src/models/SuspendedMember.js +++ /dev/null @@ -1,10 +0,0 @@ -import { Schema, model } from "mongoose"; - -const suspendedMemberSchema = new Schema({ - userId: { type: String, required: true }, - guildId: { type: String, required: true }, - roleId: { type: String, required: true }, - suspendedAt: { type: Date, default: Date.now } -}); - -export default model("SuspendedMember", suspendedMemberSchema); \ No newline at end of file diff --git a/src/models/Verification.js b/src/models/Verification.js deleted file mode 100644 index 0b781b8..0000000 --- a/src/models/Verification.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Schema, model } from "mongoose"; - -const verificationSchema = new Schema({ - guildId: { type: String, required: true }, - userId: { type: String, required: true }, - captchaAnswer: { type: String, required: true }, - createdAt: { type: Date, default: Date.now, expires: 3600 } -}); - -verificationSchema.index({ guildId: 1, userId: 1 }, { unique: true }); - -export default model("Verification", verificationSchema); \ No newline at end of file diff --git a/src/preconditions/OwnerOnly.ts b/src/preconditions/OwnerOnly.ts new file mode 100644 index 0000000..40db6a5 --- /dev/null +++ b/src/preconditions/OwnerOnly.ts @@ -0,0 +1,42 @@ +import { Precondition } from "@sapphire/framework"; +import { + type CommandInteraction, + type ContextMenuCommandInteraction, + type Message, +} from "discord.js"; + +export class OwnerOnly extends Precondition { + public override async messageRun(message: Message) { + return this.checkOwner(message.member?.id, message.guild); + } + + public override async chatInputRun(interaction: CommandInteraction) { + return this.checkOwner(interaction.user.id, interaction.guild); + } + + public override async contextMenuRun( + interaction: ContextMenuCommandInteraction, + ) { + return this.checkOwner(interaction.user.id, interaction.guild); + } + + private checkOwner(userId: string | undefined, guild: Message["guild"]) { + if (!guild) { + return this.error({ + message: "This command can only be used in a server.", + }); + } + + return userId === guild.ownerId + ? this.ok() + : this.error({ + message: "You must be the owner to run this command!", + }); + } +} + +declare module "@sapphire/framework" { + interface Preconditions { + OwnerOnly: never; + } +} diff --git a/src/prefixCommands/counting/resetcount.js b/src/prefixCommands/counting/resetcount.js deleted file mode 100644 index d7b815a..0000000 --- a/src/prefixCommands/counting/resetcount.js +++ /dev/null @@ -1,22 +0,0 @@ -import { PermissionFlagsBits } from "discord.js"; -import data from "../../../config.json" with { type: "json" }; -import { counts } from "../../states/counting.js"; - -const { serverConfig } = data; - -export default { - name: "resetcount", - description: "Resets the counting channel count.", - permissionsRequired: [PermissionFlagsBits.Administrator], - callback(client, message, args) { - try { - const guildId = message.guild.id; - const channelId = serverConfig.countingChannel; - const key = `${guildId}-${channelId}`; - counts.set(key, { lastNum: 0, lastUser: null, saves: 3 }); - message.reply("Counter has been reset."); - } catch (err) { - console.error("Error resetting count:", err); - } - }, -}; diff --git a/src/prefixCommands/counting/setcount.js b/src/prefixCommands/counting/setcount.js deleted file mode 100644 index 0e835b4..0000000 --- a/src/prefixCommands/counting/setcount.js +++ /dev/null @@ -1,36 +0,0 @@ -import { EmbedBuilder, PermissionFlagsBits } from "discord.js"; -import data from "../../../config.json" with { type: "json" }; -import { counts } from "../../states/counting.js"; - -const { serverConfig } = data; - -export default { - name: "setcount", - description: "Sets the counting channel count.", - permissionsRequired: [PermissionFlagsBits.Administrator], - async callback(client, message, args) { - try { - const guildId = message.guild.id; - const channelId = serverConfig.countingChannel; - const key = `${guildId}-${channelId}`; - counts.set(key, { - lastNum: parseInt(args[0], 10) || 0, - lastUser: null, - saves: parseInt(args[1], 10) || 0, - }); - - const embed = new EmbedBuilder() - .setTitle("Counter Updated") - .setDescription( - `The counter has been set to **${args[0]}**.\nNext number should be **${ - parseInt(args[0], 10) + 1 - }**.`, - ) - .setColor(0x5865f2); - - await message.reply({ embeds: [embed], ephemeral: false }); - } catch (err) { - console.error("Error setting count:", err); - } - }, -}; diff --git a/src/prefixCommands/misc/afk.js b/src/prefixCommands/misc/afk.js deleted file mode 100644 index 80a5a00..0000000 --- a/src/prefixCommands/misc/afk.js +++ /dev/null @@ -1,29 +0,0 @@ -import { EmbedBuilder } from "discord.js"; -import { afks } from "../../states/afk.js"; - -export default { - name: "afk", - description: "Set your status to AFK", - callback(client, message, args) { - try { - const reason = args.join(" ") || undefined; - const timestamp = new Date().toISOString(); - - afks.set(message.author.id, { - reason, - timestamp, - }); - const embed = new EmbedBuilder() - .setAuthor({ - name: message.author.tag, - iconURL: message.author.displayAvatarURL(), - }) - .setTitle("AFK Status Set") - .setDescription(`You are now AFK${reason ? `: ${reason}` : ""}.`) - .setColor(0x2b2d31); - message.reply({ embeds: [embed] }); - } catch (err) { - console.error(err); - } - }, -}; diff --git a/src/prefixCommands/misc/ping.js b/src/prefixCommands/misc/ping.js deleted file mode 100644 index 63b96bc..0000000 --- a/src/prefixCommands/misc/ping.js +++ /dev/null @@ -1,12 +0,0 @@ -export default { - name: "ping", - description: "Pong!", - callback(client, message, args) { - try { - const ping = Date.now() - message.createdTimestamp; - message.reply(`Pong! ${ping}ms | Websocket: ${client.ws.ping}ms`); - } catch (err) { - console.error(err); - } - }, -}; diff --git a/src/prefixCommands/misc/postrules.js b/src/prefixCommands/misc/postrules.js deleted file mode 100644 index e57fdb9..0000000 --- a/src/prefixCommands/misc/postrules.js +++ /dev/null @@ -1,23 +0,0 @@ -import { EmbedBuilder } from "discord.js"; -import rulesData from "../../data/rules.json" with { type: "json" }; - -export default { - name: "postrules", - description: "Posts the server rules in the current channel.", - callback: (client, message, args) => { - try { - const rulesText = rulesData - .map( - (rule) => - `**${rule.t}**\n${rule.pts.map((pt) => `↳ ${pt}`).join("\n")}\n`, - ) - .join("\n"); - - const embed = new EmbedBuilder() - .setTitle("πŸ“œ DevHub Server Rules") - .setDescription(rulesText) - .setColor(0x5865f2); - return message.channel.send({ embeds: [embed] }); - } catch (err) {} - }, -}; diff --git a/src/prefixCommands/misc/profile.js b/src/prefixCommands/misc/profile.js deleted file mode 100644 index abd3224..0000000 --- a/src/prefixCommands/misc/profile.js +++ /dev/null @@ -1,70 +0,0 @@ -import data from "../../../config.json" with { type: "json" }; -import Profile from "../../models/Profile.js"; -import buildProfileMessage from "../../utils/buildProfileMessage.js"; - -const { serverConfig } = data; - -export default { - name: "profile", - description: "View a user's profile", - aliases: ["pfp", "whois", "i", "pro"], - callback: async (client, message, args) => { - if (message.author.bot) return; - - // check if the user mentioned someone, or dropped in someone's id, otherwise show their own profile - const target = - message.mentions.users.first() || - (args[0] ? await client.users.fetch(args[0]).catch(() => null) : null) || - message.author; - const member = await message.guild.members.fetch(target.id); - - const { badgeRoles, badgeEmojis } = serverConfig; - - // Badges - const badges = Object.entries(badgeRoles) - .filter(([key, roleId]) => member.roles.cache.has(roleId)) - .map(([key]) => { - const emojiId = badgeEmojis[key]; - return emojiId ? `<:${key}:${emojiId}>` : null; - }) - .filter(Boolean); - - const badgeString = badges.length ? `${badges.join(" ")}` : ""; - - // Database profile - const profile = await Profile.findOne({ userId: target.id }); - - const bio = profile?.bio; - const country = profile?.country; - const age = profile?.age; - const stack = profile?.stack; - const github = profile?.github; - const portfolio = profile?.portfolio; - const hobbies = profile?.hobbies; - - const joined = member.joinedAt - ? member.joinedAt.toLocaleDateString("en-US", { - month: "short", - year: "numeric", - }) - : "Unknown"; - - const payload = buildProfileMessage({ - target, - member, - profile: { - bio, - country, - age, - stack, - github, - portfolio, - hobbies, - }, - joined, - badgeString, - }); - - await message.reply(payload); - }, -}; diff --git a/src/prefixCommands/misc/snowflake.js b/src/prefixCommands/misc/snowflake.js deleted file mode 100644 index 6abba16..0000000 --- a/src/prefixCommands/misc/snowflake.js +++ /dev/null @@ -1,70 +0,0 @@ -import { EmbedBuilder } from "discord.js"; - -export default { - name: "snowflake", - description: - "Decodes a Discord Snowflake ID to extract its creation metadata.", - aliases: ["sf"], - - async callback(client, message, args) { - const idStr = args[0]; - - if (!idStr) { - return message.reply( - "❌ Please provide a valid Discord ID to decode. Example: `p!snowflake 123456789012345678`", - ); - } - - if (!/^\d+$/.test(idStr)) { - return message.reply( - "❌ That doesn't look like a valid Discord ID. It must contain numbers only.", - ); - } - - try { - const id = BigInt(idStr); - - const DISCORD_EPOCH = 1420070400000n; - - const timestampMs = Number((id >> 22n) + DISCORD_EPOCH); - const workerId = Number((id >> 17n) & 0x1fn); - const processId = Number((id >> 12n) & 0x1fn); - const increment = Number(id & 0xfffn); - - const date = new Date(timestampMs); - const unixTimestamp = Math.floor(timestampMs / 1000); - - const embed = new EmbedBuilder() - .setTitle("❄️ Snowflake Decoder Result") - .setColor("#5865F2") - .setDescription(`Decoded metadata for raw ID: \`${idStr}\``) - .addFields( - { name: "Creation Date", value: date.toUTCString(), inline: false }, - { - name: "Relative Time", - value: ``, - inline: true, - }, - { - name: "Unix Milliseconds", - value: `\`${timestampMs}\``, - inline: true, - }, - { name: "Worker ID", value: `\`${workerId}\``, inline: true }, - { name: "Process ID", value: `\`${processId}\``, inline: true }, - { name: "Increment Index", value: `\`${increment}\``, inline: true }, - ) - .setFooter({ - text: `Requested by ${message.author.tag}`, - iconURL: message.author.displayAvatarURL(), - }); - - return message.reply({ embeds: [embed] }); - } catch (error) { - console.error("Snowflake processing error:", error); - return message.reply( - "❌ An error occurred while decoding that ID. Make sure it's a valid 64-bit integer.", - ); - } - }, -}; diff --git a/src/prefixCommands/static/partnershipinfo.js b/src/prefixCommands/static/partnershipinfo.js deleted file mode 100644 index a2f07f2..0000000 --- a/src/prefixCommands/static/partnershipinfo.js +++ /dev/null @@ -1,54 +0,0 @@ -import { EmbedBuilder } from "discord.js"; -import data from "../../../config.json" with { type: "json" }; - -const { serverConfig } = data; - -export default { - name: "partnershipinfo", - description: "Provides information about partnership.", - alias: ["partner", "partnership", "partnerinfo"], - callback: (client, message, args) => { - try { - const ticketChannelId = serverConfig.ticketChannel; - const ticketInfo = `If you're interested in partnering with us, feel free to open a ticket and tell us a bit about your server. Partnerships are a great way for communities to support each other through cross-promotion, collaboration, and shared growth within the tech space. - -To open a partnership ticket, head over to <#${ticketChannelId}> and select the **β€œPartnership”** option from the dropdown menu. You’ll be guided through a short form where you can provide details about your server. - -**Partnership Requirements:** - -- Your server must have **at least 100 members**. -- The server should be **active**, with regular conversations and community engagement. -- Your community must be **Tech / IT related** (programming, development, cybersecurity, AI, etc). -- **SFW only** β€” servers containing NSFW or inappropriate content will not be considered. -- **Community must be enabled** on your Discord server. -- The server should have a **clear purpose or theme** that members can easily understand. -- Channels should be **well organized with a clean structure**. -- A **moderation team** should be present to maintain the server. -- **Server rules must be visible and accessible** to all members. -- The server must be **at least 2 weeks old**. -- You must provide a **permanent (non-expiring) invite link**. -- Your server must have a **partnerships channel** where our partnership message can remain visible. - -**Partnership Benefits:** - -- **Cross-promotion** between both communities through partnership channels. -- Increased **visibility and exposure** for your server within the DevHub community. -- Opportunities for **community collaborations** such as coding events, hackathons, or learning sessions. -- Ability to **share announcements or major updates** with our community when relevant. -- **Mutual support between staff teams**, including communication regarding community issues. -- Ability to submit **ban requests** to help keep both communities safe. -`; - - const embed = new EmbedBuilder() - .setTitle("πŸ“˜ Partnership Info") - .setDescription(ticketInfo.trim()) - .setColor(0x5865f2) - .setFooter({ - text: `Requested by ${message.author.tag}`, - iconURL: message.author.displayAvatarURL(), - }) - .setTimestamp(); - return message.reply({ embeds: [embed] }); - } catch (err) {} - }, -}; diff --git a/src/prefixCommands/static/suggestinfo.js b/src/prefixCommands/static/suggestinfo.js deleted file mode 100644 index 7bbf64c..0000000 --- a/src/prefixCommands/static/suggestinfo.js +++ /dev/null @@ -1,45 +0,0 @@ -import { EmbedBuilder } from "discord.js"; - -export default { - name: "suggestinfo", - description: "Provides information about /suggest command.", - aliases: ["suggestioninfo"], - callback: (client, message, args) => { - try { - const suggestionInfo = `Use the \`/suggest\` command anywhere in the server to share ideas or improvements with the community. -### Command Syntax -\`/suggest [image]\` -- **suggestion** *(string, required)*: The idea or feedback you want to propose. -- **image** *(attachment, optional)*: An optional image to support your suggestion (recommended if available). -### What Happens Next -- The bot will post your suggestion in the suggestions channel. -- Reaction emojis will be automatically added for voting. -### Voting Reactions -- πŸ‘ β€” **Upvote** (I support this!) -- πŸ‘Ž β€” **Downvote** (Not a fan) -- 🀷 β€” **Neutral / Unsure** -- πŸ•’ β€” **Queue** (suggestion acknowledged, pending review) -- βœ… β€” **Implemented** (set by admins/mods when suggestion is applied) -- ❌ β€” **Rejected / Not possible** -### ℹ️ Extra Info -- πŸ’¬ You can **create a thread** under any suggestion to discuss details. -- πŸ›‘οΈ Admins/mods may pin or highlight popular suggestions for visibility or keep as memory. -- πŸš€ Be clear and concise. actionable suggestions get the most traction. -- 🎨 Images, mockups, or examples make your suggestion stronger and easier to understand. -- 🀝 Respect others’ ideas. constructive discussion only. - -✨ *Your feedback shapes the community. Don’t hesitate to drop your ideas!* -`; - - const embed = new EmbedBuilder() - .setTitle("πŸ“˜ Suggestion Guide") - .setDescription(suggestionInfo.trim()) - .setColor(0x5865f2) - .setFooter({ - text: `Requested by ${message.author.tag} β€’ Use /suggest to send your suggestion`, - iconURL: message.author.displayAvatarURL(), - }); - return message.reply({ embeds: [embed] }); - } catch (err) {} - }, -}; diff --git a/src/prefixCommands/static/ticketinfo.js b/src/prefixCommands/static/ticketinfo.js deleted file mode 100644 index a1f2425..0000000 --- a/src/prefixCommands/static/ticketinfo.js +++ /dev/null @@ -1,34 +0,0 @@ -import { EmbedBuilder } from "discord.js"; -import data from "../../../config.json" with { type: "json" }; - -const { serverConfig } = data; - -export default { - name: "ticketinfo", - description: "Provides information about tickets.", - alias: ["ticketsinfo", "ticketinginfo"], - callback: (client, message, args) => { - try { - const ticketChannelId = serverConfig.ticketChannel; - const ticketInfo = `Tickets are the best way to get help and ensure moderators can respond quickly. Here’s what you can use them for: -- 🧩 General Support: For questions, technical issues, or anything else you need assistance with, tickets help us track and resolve them. -- 🎭 Request Unban / Unmute: If you or a friend need to appeal a ban, mute or suspend, open a ticket and provide the details. -- 🚨 Report User: If you need to report someone, tickets make sure the moderators see it right away and can investigate properly. -- βš’οΈ Apply For Staff: Interested in joining our moderation team? Use a ticket to submit your application and tell us why you’d be a great fit. -- πŸ“ Other: For any other reasons, open a ticket and explain your situation. - -To open a ticket, go to <#${ticketChannelId}> and use the dropdown menu to select your ticket type. You’ll be guided through a simple form to explain your reason. I will handle the process, create a private channel for your case, and keep everything neat and secure. Thanks for helping us keep the community clean ✨`; - - const embed = new EmbedBuilder() - .setTitle("πŸ“˜ Ticket Guide") - .setDescription(ticketInfo.trim()) - .setColor(0x5865f2) - .setFooter({ - text: `Requested by ${message.author.tag}`, - iconURL: message.author.displayAvatarURL(), - }) - .setTimestamp(); - return message.reply({ embeds: [embed] }); - } catch (err) {} - }, -}; diff --git a/src/prefixCommands/utilities/countinglb.js b/src/prefixCommands/utilities/countinglb.js deleted file mode 100644 index f6cbb47..0000000 --- a/src/prefixCommands/utilities/countinglb.js +++ /dev/null @@ -1,43 +0,0 @@ -import { EmbedBuilder } from "discord.js"; -import Counting from "../../models/Counting.js"; - -export default { - name: "countinglb", - description: "View the counting leaderboard", - aliases: ["clb", "countlb", "countingtop"], - callback: async (client, message, args) => { - try { - if (message.author.bot) return; - - const counts = await Counting.find() - .sort({ counts: -1 }) - .limit(15) - .select("userId counts -_id"); - - const embed = new EmbedBuilder() - .setTitle("Counting Leaderboard") - .setColor(0x2b2d31); - - if (counts.length === 0) { - embed.setDescription("No counts yet!"); - } else { - embed.setDescription( - counts - .map((entry, index) => { - const isAuthor = entry.userId === message.author.id; - return `**${index + 1}.** <@${entry.userId}>${isAuthor ? " (You)" : ""} - **${entry.counts}**`; - }) - .join("\n") - ); - } - - await message.reply({ - embeds: [embed], - }); - } catch (error) { - console.error("Error in countinglb command:", error); - await message.reply({ - content: "An error occurred while fetching the leaderboard.", - }).catch(() => {}); - } -}, diff --git a/src/prefixCommands/utilities/hide.js b/src/prefixCommands/utilities/hide.js deleted file mode 100644 index c9184ab..0000000 --- a/src/prefixCommands/utilities/hide.js +++ /dev/null @@ -1,20 +0,0 @@ -import { PermissionFlagsBits } from "discord.js"; - -export default { - name: "hide", - description: "Hides current channel.", - permissionsRequired: [PermissionFlagsBits.Administrator], - async callback(client, message, args) { - try { - await message.channel.permissionOverwrites.edit( - message.guild.roles.everyone, - { - ViewChannel: false, - }, - ); - await message.reply("Channel has been hidden."); - } catch (err) { - console.error("Error hiding channel:", err); - } - }, -}; diff --git a/src/prefixCommands/utilities/lock.js b/src/prefixCommands/utilities/lock.js deleted file mode 100644 index fe05814..0000000 --- a/src/prefixCommands/utilities/lock.js +++ /dev/null @@ -1,30 +0,0 @@ -import { PermissionFlagsBits } from "discord.js"; - -export default { - name: "lock", - description: "Locks current channel.", - permissionsRequired: [PermissionFlagsBits.Administrator], - async callback(client, message, args) { - try { - if (args.length > 0) { - const user = message.mentions.users.first(); - if (user) { - await message.channel.permissionOverwrites.edit(user.id, { - SendMessages: false, - }); - await message.reply(`Channel has been locked for ${user.tag}.`); - return; - } - } - await message.channel.permissionOverwrites.edit( - message.guild.roles.everyone, - { - SendMessages: false, - }, - ); - await message.reply("Channel has been locked."); - } catch (err) { - console.error("Error locking channel:", err); - } - }, -}; diff --git a/src/prefixCommands/utilities/purge.js b/src/prefixCommands/utilities/purge.js deleted file mode 100644 index 651e196..0000000 --- a/src/prefixCommands/utilities/purge.js +++ /dev/null @@ -1,39 +0,0 @@ -import { EmbedBuilder, PermissionFlagsBits } from "discord.js"; - -export default { - name: "purge", - description: "Purges messages from the current channel.", - permissionsRequired: [PermissionFlagsBits.Administrator], - async callback(client, message, args) { - try { - const deleteCount = parseInt(args[0], 10); - if (isNaN(deleteCount) || deleteCount < 1 || deleteCount > 100) { - await message.reply( - "Please provide a valid number of messages to delete (1-100).", - ); - return; - } - const deletedMessages = await message.channel.bulkDelete( - deleteCount, - true, - ); - const embed = new EmbedBuilder() - .setTitle("βœ… Messages Purged") - .setDescription( - `**Channel**: ${message.channel} - **Moderator**: <@${message.author.id}> - **Deleted Messages**: ${deletedMessages.size} - `, - ) - .setColor("Green") - .setTimestamp(); - const reply = await message.channel.send({ embeds: [embed] }); - - setTimeout(async () => { - await reply.delete(); - }, 10000); - } catch (err) { - console.error("Error purging messages:", err); - } - }, -}; diff --git a/src/prefixCommands/utilities/slowmode.js b/src/prefixCommands/utilities/slowmode.js deleted file mode 100644 index 086ca9a..0000000 --- a/src/prefixCommands/utilities/slowmode.js +++ /dev/null @@ -1,24 +0,0 @@ -import { PermissionFlagsBits } from "discord.js"; - -export default { - name: "slowmode", - description: "Set slowmode for the channel. Usage: !slowmode ", - permissionsRequired: [PermissionFlagsBits.Administrator], - async callback(client, message, args) { - try { - const duration = parseInt(args[0], 10); - if (isNaN(duration) || duration < 0 || duration > 21600) { - return await message.reply( - "Please provide a valid duration in seconds (0-21600).", - ); - } - - await message.channel.setRateLimitPerUser(duration); - await message.reply( - `Slowmode has been set to ${duration == 1 ? "1 second" : `${duration} seconds`} for this channel.`, - ); - } catch (err) { - console.error(err); - } - }, -}; diff --git a/src/prefixCommands/utilities/unhide.js b/src/prefixCommands/utilities/unhide.js deleted file mode 100644 index aa5dd17..0000000 --- a/src/prefixCommands/utilities/unhide.js +++ /dev/null @@ -1,21 +0,0 @@ -import { PermissionFlagsBits } from "discord.js"; - -export default { - name: "unhide", - description: "Unhides current channel.", - aliases: ["show"], - permissionsRequired: [PermissionFlagsBits.Administrator], - async callback(client, message, args) { - try { - await message.channel.permissionOverwrites.edit( - message.guild.roles.everyone, - { - ViewChannel: true, - }, - ); - await message.reply("Channel has been unhidden."); - } catch (err) { - console.error("Error un hiding channel:", err); - } - }, -}; diff --git a/src/prefixCommands/utilities/unlock.js b/src/prefixCommands/utilities/unlock.js deleted file mode 100644 index 7be3ddd..0000000 --- a/src/prefixCommands/utilities/unlock.js +++ /dev/null @@ -1,28 +0,0 @@ -import { PermissionFlagsBits } from "discord.js"; - -export default { - name: "unlock", - description: "Unlocks current channel.", - permissionsRequired: [PermissionFlagsBits.Administrator], - async callback(client, message, args) { - try { - if (args.length > 0) { - const user = message.mentions.users.first(); - if (user) { - await message.channel.permissionOverwrites.delete(user.id); - await message.reply(`Channel has been unlocked for ${user.tag}.`); - return; - } - } - await message.channel.permissionOverwrites.edit( - message.guild.roles.everyone, - { - SendMessages: true, - }, - ); - await message.reply("Channel has been unlocked."); - } catch (err) { - console.error("Error unlocking channel:", err); - } - }, -}; diff --git a/src/states/afk.js b/src/states/afk.js deleted file mode 100644 index c86ba93..0000000 --- a/src/states/afk.js +++ /dev/null @@ -1 +0,0 @@ -export const afks = new Map(); diff --git a/src/states/counting.js b/src/states/counting.js deleted file mode 100644 index caa4385..0000000 --- a/src/states/counting.js +++ /dev/null @@ -1 +0,0 @@ -export const counts = new Map(); diff --git a/src/types/afk.ts b/src/types/afk.ts new file mode 100644 index 0000000..6e7d9fe --- /dev/null +++ b/src/types/afk.ts @@ -0,0 +1,4 @@ +export interface AFKDB { + reason: string | null; + mentions?: number; +} diff --git a/src/types/counting.ts b/src/types/counting.ts new file mode 100644 index 0000000..f9f2779 --- /dev/null +++ b/src/types/counting.ts @@ -0,0 +1,5 @@ +export interface CountDB { + lastUser: string; + lastCount: number; + saves: number; +} diff --git a/src/utils/areCommandsDifferent.js b/src/utils/areCommandsDifferent.js deleted file mode 100644 index 5561d04..0000000 --- a/src/utils/areCommandsDifferent.js +++ /dev/null @@ -1,55 +0,0 @@ -export default (existingCommand, localCommand) => { - const areChoicesDifferent = (existingChoices, localChoices) => { - for (const localChoice of localChoices) { - const existingChoice = existingChoices?.find( - (choice) => choice.name === localChoice.name, - ); - - if (!existingChoice) { - return true; - } - - if (localChoice.value !== existingChoice.value) { - return true; - } - } - return false; - }; - - const areOptionsDifferent = (existingOptions, localOptions) => { - for (const localOption of localOptions) { - const existingOption = existingOptions?.find( - (option) => option.name === localOption.name, - ); - - if (!existingOption) { - return true; - } - - if ( - localOption.description !== existingOption.description || - localOption.type !== existingOption.type || - (localOption.required || false) !== existingOption.required || - (localOption.choices?.length || 0) !== - (existingOption.choices?.length || 0) || - areChoicesDifferent( - localOption.choices || [], - existingOption.choices || [], - ) - ) { - return true; - } - } - return false; - }; - - if ( - existingCommand.description !== localCommand.description || - existingCommand.options?.length !== (localCommand.options?.length || 0) || - areOptionsDifferent(existingCommand.options, localCommand.options || []) - ) { - return true; - } - - return false; -}; diff --git a/src/utils/buildModal.js b/src/utils/buildModal.js deleted file mode 100644 index 2c4267d..0000000 --- a/src/utils/buildModal.js +++ /dev/null @@ -1,44 +0,0 @@ -import { - ActionRowBuilder, - ModalBuilder, - TextInputBuilder, - TextInputStyle, -} from "discord.js"; - -/** - * Build a Modal from a config object. - * config: { - * customId: string, - * title: string, - * fields: [{ customId, label, style, placeholder, required, maxLength, minLength }] - * } - */ -export default (client, config = {}) => { - const modal = new ModalBuilder() - .setCustomId(config.customId || "modal") - .setTitle(config.title || "Modal"); - - const fields = config.fields || []; - - const components = fields.map((f) => { - const input = new TextInputBuilder() - .setCustomId(f.customId) - .setLabel(f.label || f.customId) - .setStyle( - f.style === "PARAGRAPH" - ? TextInputStyle.Paragraph - : TextInputStyle.Short, - ) - .setRequired(f.required ?? true); - - if (f.placeholder) input.setPlaceholder(f.placeholder); - if (typeof f.maxLength === "number") input.setMaxLength(f.maxLength); - if (typeof f.minLength === "number") input.setMinLength(f.minLength); - - return new ActionRowBuilder().addComponents(input); - }); - - if (components.length) modal.setComponents(...components); - - return modal; -}; diff --git a/src/utils/buildProfileMessage.js b/src/utils/buildProfileMessage.js deleted file mode 100644 index 4a84734..0000000 --- a/src/utils/buildProfileMessage.js +++ /dev/null @@ -1,128 +0,0 @@ -import { ComponentType, escapeMarkdown, MessageFlags } from "discord.js"; - -const COMPONENTS_V2_FLAG = MessageFlags.IsComponentsV2; -const MAX_TEXT_LENGTH = 50; - -function truncateText(text, maxLength = MAX_TEXT_LENGTH) { - if (typeof text !== "string") return ""; - if (text.length <= maxLength) return text; - return `${text.slice(0, maxLength - 3)}...`; -} - -function buildProfileMessage({ target, member, profile, joined, badgeString }) { - const displayName = - member?.displayName || target.displayName || target.username; - const avatarUrl = target.displayAvatarURL({ size: 256 }); - - const bioText = profile?.bio - ? escapeMarkdown(profile.bio) - : "No bio set yet. (use `/edit-profile` command to edit your profile)"; - - const introText = [ - `## ${truncateText(escapeMarkdown(displayName))}`, - badgeString ? `${badgeString}` : null, - " ", - `${truncateText(escapeMarkdown(bioText))}`, - ] - .filter(Boolean) - .join("\n"); - - const fieldEntries = [ - profile?.country - ? { - name: "Country", - value: truncateText(escapeMarkdown(profile.country)), - } - : null, - profile?.age - ? { name: "Age", value: truncateText(`${profile.age}`) } - : null, - profile?.stack - ? { name: "Stack", value: truncateText(escapeMarkdown(profile.stack)) } - : null, - profile?.hobbies - ? { - name: "Hobbies", - value: truncateText(escapeMarkdown(profile.hobbies)), - } - : null, - ].filter(Boolean); - - const links = [ - profile?.github - ? { - label: truncateText("GitHub"), - url: profile.github, - } - : null, - profile?.portfolio - ? { - label: truncateText("Portfolio"), - url: profile.portfolio, - } - : null, - ].filter(Boolean); - - const infoText = [ - ...fieldEntries.map((field) => `**${field.name}:** ${field.value}`), - ].join("\n"); - - return { - content: "", - flags: COMPONENTS_V2_FLAG, - components: [ - { - type: ComponentType.Container, - accent_color: 0x2b2d31, - size: 1, - components: [ - { - type: ComponentType.Section, - components: [ - { - type: ComponentType.TextDisplay, - content: introText, - }, - ], - spacing: 2, - accessory: { - type: ComponentType.Thumbnail, - media: { - url: avatarUrl, - }, - description: `${displayName}'s avatar`, - }, - }, - { - type: ComponentType.Separator, - divider: true, - spacing: 2, - }, - { - type: ComponentType.TextDisplay, - content: infoText, - }, - ...(links.length - ? [ - { - type: ComponentType.ActionRow, - components: links.map((link) => ({ - type: ComponentType.Button, - style: 5, - label: link.label, - url: link.url, - })), - }, - ] - : []), - { - type: ComponentType.TextDisplay, - content: `Joined ${joined}`, - }, - ], - }, - ], - }; -} - -export default buildProfileMessage; diff --git a/src/utils/getAllFiles.js b/src/utils/getAllFiles.js deleted file mode 100644 index 5fcd7a7..0000000 --- a/src/utils/getAllFiles.js +++ /dev/null @@ -1,27 +0,0 @@ -import fs from "fs"; -import path from "path"; - -const getAllFiles = (directory, foldersOnly = false) => { - let fileNames = []; - const files = fs.readdirSync(directory, { withFileTypes: true }); - - for (const file of files) { - const filePath = path.join(directory, file.name); - - const normalizedPath = filePath.replace(/^[a-z]:/i, (match) => match.toUpperCase()); - - if (file.isDirectory()) { - if (foldersOnly) { - fileNames.push(normalizedPath); - } - fileNames.push(...getAllFiles(normalizedPath, foldersOnly)); - } else if (file.isFile() && !foldersOnly) { - fileNames.push(normalizedPath); - } - } - - return fileNames; -}; - - -export default getAllFiles; diff --git a/src/utils/getApplicationCommands.js b/src/utils/getApplicationCommands.js deleted file mode 100644 index d56b282..0000000 --- a/src/utils/getApplicationCommands.js +++ /dev/null @@ -1,13 +0,0 @@ -export default async (client, guildId) => { - let applicationCommands; - - if (guildId) { - const guild = await client.guilds.fetch(guildId); - applicationCommands = guild.commands; - } else { - applicationCommands = await client.application.commands; - } - - await applicationCommands.fetch(); - return applicationCommands; -}; diff --git a/src/utils/getLocalCommands.js b/src/utils/getLocalCommands.js deleted file mode 100644 index 056dda3..0000000 --- a/src/utils/getLocalCommands.js +++ /dev/null @@ -1,33 +0,0 @@ -import path from "path"; -import { fileURLToPath, pathToFileURL } from "url"; -import getAllFiles from "./getAllFiles.js"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -export default async (exceptions = []) => { - let localCommands = []; - - const commandCategories = getAllFiles( - path.join(__dirname, "..", "commands"), - true, - ); - - for (const commandCategory of commandCategories) { - const commandFiles = getAllFiles(commandCategory); - - for (const commandFile of commandFiles) { - const commandModule = await import(pathToFileURL(path.resolve(commandFile)).href); - const commandObject = - (commandModule && commandModule.default) || commandModule; - - if (exceptions.includes(commandObject.name)) { - continue; - } - - localCommands.push(commandObject); - } - } - - return localCommands; -}; diff --git a/src/utils/sendEmbed.js b/src/utils/sendEmbed.js deleted file mode 100644 index 6647b0b..0000000 --- a/src/utils/sendEmbed.js +++ /dev/null @@ -1,27 +0,0 @@ -import { EmbedBuilder } from "discord.js"; - -export default ({ - interaction, - channel = interaction.channel, - title, - description, - color = 0x5865f2, - fields = [], - footer, - reply = false, -}) => { - const embed = new EmbedBuilder() - .setTitle(title || "") - .setDescription(description || "") - .setColor(color); - - if (fields && fields.length) embed.addFields(fields); - if (footer) embed.setFooter({ text: footer }); - - const shouldEdit = - !!reply || !!interaction?.deferred || !!interaction?.replied; - - if (shouldEdit) return interaction.editReply({ embeds: [embed] }); - - return channel.send({ embeds: [embed] }); -}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..ab99e75 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "outDir": "./dist", + + "module": "nodenext", + "target": "esnext", + "types": [], + + "sourceMap": true, + "declaration": true, + "declarationMap": true, + + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + + "strict": true, + "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noEmit": true, + "allowImportingTsExtensions": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true + } +} diff --git a/tsup.config.ts b/tsup.config.ts new file mode 100644 index 0000000..65449a1 --- /dev/null +++ b/tsup.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm"], + outDir: "dist", + dts: false, + minifyWhitespace: true, + minifySyntax: true, + external: ["dotenv"], +});