Compare commits

...

38 Commits

Author SHA1 Message Date
045c89a6cb chore: some prompt stuff
Some checks failed
Publish Docker image / Push Docker image to Docker Hub (push) Failing after 33s
2026-04-03 23:30:07 +02:00
8dcd2de683 chore: switch models again 2026-04-03 23:28:39 +02:00
e3c63632a1 chore: switch models 2026-04-03 23:27:13 +02:00
a6df2e4f31 fix: dont use the imports
Some checks failed
Publish Docker image / Push Docker image to Docker Hub (push) Failing after 13m0s
2026-04-02 17:47:59 +02:00
502811ca9f fix: disable scripts 2026-04-02 17:44:54 +02:00
58dd540ea9 fix: use bun 2026-04-02 17:42:24 +02:00
589f53c65c fix: install sern cli 2026-04-02 17:41:17 +02:00
66594ce8bd chore: run db migrations 2026-04-02 17:32:25 +02:00
effbe7d9c5 feat: the rewrite (#55) 2026-04-02 17:09:04 +02:00
0e8703629d fix: use node instead of nodemon
Some checks failed
Publish Docker image / Push Docker image to Docker Hub (push) Has been cancelled
2025-09-08 22:58:22 +02:00
b20a969dee chore: nixpacks deployment 2025-09-08 22:44:01 +02:00
b82784608f fix: racoon and capybara images command 2024-10-04 16:55:31 +02:00
ea1d086fd0 fix: docker builds 2 2024-09-20 19:42:21 +02:00
b84260901d fix: docker builds 2024-09-20 19:37:32 +02:00
8ac9c16945 refactor: basically everything, move to src dir, move to sern build, publisher, v4, fix commands 2024-09-20 19:32:03 +02:00
8aeebb1164 fix: v ig on thread 2024-07-28 17:57:39 +02:00
fa23042c99 ci: update docker yml 2024-07-28 15:12:10 +02:00
2aafce2429 docs: remove discordapp attachment 2024-07-20 00:01:34 +02:00
8d5c962049 fix: some random bugs 2024-07-09 23:36:57 +02:00
37d983e150 chore: change model to mistral 2024-07-09 23:29:24 +02:00
3b9acf6f29 chore: empty redeploy commit 2024-07-09 23:20:20 +02:00
51ea593bcd copy all 2024-04-23 19:42:23 +02:00
8112f232e3 add corepack 2024-04-23 19:39:45 +02:00
214c35a7e6 docker buildx 2024-04-23 19:37:19 +02:00
d208f6b8c7 fix: why is ts not installing 2024-04-23 19:31:55 +02:00
0b8f23cefd fix: update tsc version 2024-04-23 19:27:52 +02:00
c95ceb1539 chore: set version 2024-04-23 19:21:14 +02:00
0654ce2bfd fix: some small stuff 2024-04-23 17:20:06 +02:00
b84bd0a250 chore: change to v!ig instead of "ig" 2024-04-22 21:33:42 +02:00
8005ac0699 La year inactivity update! (#48)
* feat: non t message deletion

* feat: cloudflare ai!

* feat: image classification and llama 3

* feat: image classification and infinitecraft

* feat: add initial find and lower the paste length

* chore: add devServer boolean to gpt
2024-04-22 21:25:52 +02:00
ecada7600e fix: the goofy ahh youtube notifications bug 2024-04-02 19:54:22 +02:00
73e397be5b fix: util folder getting copied over to root 2023-11-29 20:36:19 +01:00
0f08d35876 chore: empty commit 2023-11-04 23:04:52 +01:00
116f0be0b2 feat: spotify link cleaner, bye scam links 2023-11-04 22:53:10 +01:00
43c0b40703 Merge pull request #39 from SrIzan10/snyk-fix-f8a2f0a23fb4b30c3b5997999e893e30
[Snyk] Security upgrade systeminformation from 5.17.12 to 5.21.7
2023-10-11 22:06:44 +02:00
snyk-bot
10aa847aba fix: package.json to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-SYSTEMINFORMATION-5914637
2023-09-22 17:01:02 +00:00
d786e40af3 fix: ts type errors and migrate to v3 2023-09-04 16:41:45 +02:00
a2e1f7d9ac fix: various stuff 2023-09-03 21:46:33 +02:00
159 changed files with 1062808 additions and 6675 deletions

View File

@@ -0,0 +1,7 @@
{
"image": "mcr.microsoft.com/devcontainers/universal:2",
"runArgs": ["--device=/dev/net/tun"],
"features": {
"ghcr.io/tailscale/codespace/tailscale": {}
}
}

9
.dockerignore Normal file
View File

@@ -0,0 +1,9 @@
.env*
node_modules/
json.sqlite
dist/
*giveaway*
.sern
/generated/generated/prisma
prisma/vinci.db
!.env.example

View File

@@ -1,8 +1,27 @@
# THIS IS OUTDATED
DISCORD_TOKEN=
PREFIX=
# Database (before rewrites)
MONGODB=
# API keys
CATAPI=
DOGAPI=
TWITTER=
# request makesweet creator for this
MAKESWEET=
GENIUS=
SPOTIFY_CLIENT=
SPOTIFY_SECRET=
CF_AI_TOKEN=
CF_AI_ACC=
# Guild configs
GUILDID=
SUGGESTIONS_CHANNEL=
MODLOGS_CHANNEL=
JOINSANDLEAVES_CHANNEL=
SOCIALS_CHANNEL=
GIVEAWAYS_CHANNEL=
MCFORM_CHANNEL=
CHATGPT_CHANNEL=
T_CHANNEL=
TOKEN=token
PREFIX=v!
MONGODB=mongodb://
HYPIXEL_API=API_KEY
YOURLS_KEY=YOURLS_SIGNATURE
YOUTUBE_API=
NODE_ENV=development

View File

@@ -22,10 +22,12 @@ jobs:
- name: Check out the repo
uses: actions/checkout@v3
- name: Log in to Sr Izan's container registry
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
with:
registry: containers.srizan.dev
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
@@ -33,7 +35,7 @@ jobs:
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: containers.srizan.dev/vinci
images: srizan10/vinci
tags: latest
- name: Build and push Docker image
@@ -50,5 +52,5 @@ jobs:
AUTH_HEADER: ${{ secrets.WHSERVER_TOKEN }}
run: |
curl -X POST \
-H "Authorization: Bearer $AUTH_HEADER" \
https://webhooks.srizan.dev/hooks/vinci
-H "Authorization: $AUTH_HEADER" \
https://webhooks.srizan.dev/hooks/vinci

11
.gitignore vendored
View File

@@ -1,6 +1,11 @@
.env
.env.dev
.env*
node_modules/
json.sqlite
dist/
*giveaway*
*giveaway*
.sern
/generated/generated/prisma
src/utils/db/dict.db
prisma/vinci.db
!.env.example
.codex

8
.idea/.gitignore generated vendored
View File

@@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@@ -1,65 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<HTMLCodeStyleSettings>
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
<option name="HTML_QUOTE_STYLE" value="Single" />
<option name="HTML_ENFORCE_QUOTES" value="true" />
</HTMLCodeStyleSettings>
<JSCodeStyleSettings version="0">
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
<option name="USE_DOUBLE_QUOTES" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
<option name="SPACES_WITHIN_IMPORTS" value="true" />
</JSCodeStyleSettings>
<TypeScriptCodeStyleSettings version="0">
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
<option name="USE_DOUBLE_QUOTES" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
<option name="SPACES_WITHIN_IMPORTS" value="true" />
</TypeScriptCodeStyleSettings>
<VueCodeStyleSettings>
<option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
<option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
</VueCodeStyleSettings>
<codeStyleSettings language="HTML">
<option name="SOFT_MARGINS" value="80" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JavaScript">
<option name="SOFT_MARGINS" value="80" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="TypeScript">
<option name="SOFT_MARGINS" value="80" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="Vue">
<option name="SOFT_MARGINS" value="80" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

View File

@@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

7
.idea/discord.xml generated
View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DiscordProjectSettings">
<option name="show" value="PROJECT_FILES" />
<option name="description" value="" />
</component>
</project>

View File

@@ -1,10 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" />
<option name="processLiterals" value="true" />
<option name="processComments" value="true" />
</inspection_tool>
</profile>
</component>

6
.idea/misc.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
.idea/modules.xml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/vinci.iml" filepath="$PROJECT_DIR$/.idea/vinci.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

9
.idea/vinci.iml generated
View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -1,5 +1,8 @@
{
"tabWidth": 2,
"useTabs": true,
"singleQuote": true
"useTabs": false,
"printWidth": 100,
"tabWidth": 2,
"singleQuote": true,
"trailingComma": "es5",
"semi": true
}

View File

@@ -1,3 +1,7 @@
{
"dotenv.enableAutocloaking": false
"dotenv.enableAutocloaking": false,
"editor.tabSize": 2,
"editor.detectIndentation": false,
"editor.insertSpaces": true,
"editor.rulers": [100]
}

View File

@@ -1,32 +1,39 @@
FROM node:lts
# Build stage
FROM node:lts-alpine AS build
FROM oven/bun:alpine AS base
WORKDIR /app
RUN bun add -g @sern/cli
RUN apk add --no-cache --virtual .gyp python3 make g++
COPY package.json yarn.lock ./
RUN yarn
# Install dependencies
FROM base AS deps
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile --ignore-scripts
# Build the application
FROM base AS build
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN yarn build
RUN yarn cache clean
# Final stage
FROM node:lts-alpine AS final
RUN bun prisma generate
RUN bun run build
# Production image
FROM base AS runner
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/schemas ./schemas
COPY --from=build /app/util ./
COPY --from=build /app/images ./images
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/package.json ./package.json
RUN apk add --no-cache ffmpeg msttcorefonts-installer fontconfig && \
ENV NODE_ENV=production
# Install system dependencies
RUN apk add --no-cache ffmpeg fontconfig ttf-opensans msttcorefonts-installer && \
update-ms-fonts && \
fc-cache -f
CMD ["node", "dist/index.js"]
RUN mkdir -p ./src/utils/db && \
wget -O ./src/utils/db/dict.db https://github.com/SrIzan10/vinci/releases/download/dict-1/dict.db
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
COPY --from=build /app/assets ./assets
COPY --from=build /app/images ./images
COPY --from=build /app/.sern ./.sern
COPY --from=build /app/package.json ./package.json
COPY --from=build /app/prisma ./prisma
CMD ["sh", "-c", "bun run db:migrate && bun dist/index.js"]

View File

@@ -1,35 +1,46 @@
vinci bot
# vinci v2
# little shoutout
this discord bot has been made with [sern handler](https://sern.dev) and MAN I LOVE THIS HANDLER.
Vinci v2 is a rewrite of my first JS project, a discord bot for [my favorite book series](https://maraturing.com) server. It aims to improve the code quality of the primary codebase, full of bugs and spaghetti code.
the maintainers helped me out from day one of the bot (and also teached me a lotta js along the way)
It is written, as always, under the [sern](https://sern.dev) framework.
so tysm for everything, and I hope I can continue making new bots with this <3
It is 85% done, with hardest commands implemented.
(also, fellow programmer, consider using it please)
This is a bot submission for [Converge](https://converge.hackclub.com) and [Summer of Making](https://summer.hackclub.com).
# badges yes sir
[![CodeFactor](https://www.codefactor.io/repository/github/srizan10/vinci/badge)](https://www.codefactor.io/repository/github/srizan10/vinci) [![wakatime](https://wakatime.com/badge/user/4ad16edf-eadc-48d9-b010-26f275fe0be6/project/120bd895-55e3-42fe-894b-bd974f6f7312.svg)](https://wakatime.com/badge/user/4ad16edf-eadc-48d9-b010-26f275fe0be6/project/120bd895-55e3-42fe-894b-bd974f6f7312)
## New features
- More fun games
- Modern typescript and discord.js
- SQLite + Prisma instead of MongoDB + Mongoose
- Less API queries and more performance by using local datasets (like the Spanish dictionary)
# warning and stuff
# Available commands
- `/rolemenu` - Role selection menu (owner only)
- `/sugerencias` - Send a suggestion to the channel with upvote/downvote buttons
- `/mcform` - Submit a form to join a Minecraft server
- `/ip` - Get information about the Minecraft server IP
- `/acortar` - Shorten a URL
- `/wikipedia` - Search Wikipedia (Spanish/English)
- `/8ball` - Ask the magic 8-ball a question
- `/a` - Autogenerated "A" text with user autocomplete
- `/chiste` - Get a random joke from a local dataset
- `/google` - The most useless Google search command
- `/hangman` - Play a game of hangman
- `/makesweet` - Generate a heart locket image
- `/megamind` - Generate a Megamind meme with custom text
- `/palabra` - Returns a random Spanish word. That is it.
- `/rps` - Play rock paper scissors against someone
### Other stuff
- Bonzify - Text-to-speech with Bonzi Buddy voice
- Cursivify - Italicize message text
- Image classification - Classify images using Cloudflare AI
- AI chat - Chat with AI on a channel
this bot has been entirely coded by me, with absolutely no youtube tutorials.
the code is here for transparency purposes and it's not made to be hosted by third parties.
# heres a roadmap (REALLY OUTDATED)
- ~~form to apply for the minecraft server~~ DONE!
- ~~moderation commands~~ DONE!
- ~~welcome to users~~ DONE!
- modmail
- ~~socials notification system~~ DONE!
- chatbot using IBM's AI (thanks @gosevil for the idea)
- ~~joke command~~
<!--<img src="https://srizan.s-ul.eu/RddzT2f9">-->
<img src="https://cdn.discordapp.com/attachments/928230817673641995/1036390945945559140/makesweet-hbt4h3.gif">
by @Oliverlg8
10 stars! tysm!
## Development setup
1. Clone the repository
2. Run `bun install`
3. Install the sern cli: `npm install -g @sern/cli`
4. Create a copy of `.env.example` and rename it to `.env`
5. Fill in the file
6. Run `bunx prisma migrate dev` to set up the database
7. Run `bun dev`

55
TODO.md Normal file
View File

@@ -0,0 +1,55 @@
# Slash Commands
## Fun Commands
- [ ] /animal - Animal pictures with voting system (cat, dog, capybara, fox, raccoon)
- [x] /chiste - Joke command fetching from API
- [x] /rps - Rock Paper Scissors game
- [x] /8ball - Magic 8-ball responses
- [x] /megamind - Megamind meme generator with canvas
- [x] /makesweet - Heart locket image generator
- [x] /a - Custom command with user autocomplete
## Miscellaneous Commands
- [x] /rolemenu - Role selection menu (owner only)
- [ ] /creditos - Bot credits and acknowledgments
- [x] ~~/infinitecraft - InfiniteCraft recipe solver~~
- [ ] /letra - Song lyrics search via Genius API
- [x] /google - Google search results
- [x] /sugerencias - Suggestion system with upvote/downvote
- [x] /wikipedia - Wikipedia search (Spanish/English)
- [ ] /faq - FAQ system with Minecraft questions
- [ ] ~~/afk - AFK status management~~
- [x] /acortar - URL shortener
## Minecraft Commands
- [x] /ip - Minecraft server IP information
- [x] /mcform - Minecraft form submission
# Button Handlers
- [x] suggestions-yes - Upvote button handler
- [x] suggestions-no - Downvote button handler
- [x] suggestions-yes-who - Show upvoters
- [x] suggestions-no-who - Show downvoters
# Context Menu Commands
- [x] bonzify - Text-to-speech with Bonzi Buddy voice
- [x] cursivify - Italicize message text
- [x] image-classification - Cloudflare AI image classification
# Message driven functions
- [x] AI chat
# Utility Systems to Rewrite
- [x] Resolver - Role/user resolution utility
- [x] Wikipedia utility - Wikipedia search helper
# Background Services
- [x] ~YouTube notifications system~ using rss instead
- [x] Birthday checker service
- [x] Activity status rotation
# Database
- [x] Migration to sqlite
# Other
- [ ] Figure out fonts

1
assets/chistes.json Normal file

File diff suppressed because one or more lines are too long

1059783
assets/icRecipes.json Normal file

File diff suppressed because it is too large Load Diff

584
bun.lock Normal file
View File

@@ -0,0 +1,584 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "ts-example",
"dependencies": {
"@napi-rs/canvas": "^0.1.72",
"@prisma/client": "^6.10.1",
"@sern/handler": "^4.2.4",
"@sern/publisher": "1.1.2",
"discord.js": "^14.21.0",
"dotenv": "^16.3.1",
"execa": "^9.6.0",
"mongodb": "^6.17.0",
"node-html-parser": "^7.0.1",
"openai": "^5.10.2",
"rockpaperscissors-checker": "^1.2.0",
"sharp": "^0.34.2",
},
"devDependencies": {
"@sern/cli": "^1.4.0",
"@types/bun": "^1.2.18",
"@types/mongodb": "^4.0.7",
"@types/node": "^17.0.25",
"prisma": "^6.10.1",
"typescript": "^5.0",
},
},
},
"packages": {
"@discordjs/builders": ["@discordjs/builders@1.11.2", "", { "dependencies": { "@discordjs/formatters": "^0.6.1", "@discordjs/util": "^1.1.1", "@sapphire/shapeshift": "^4.0.0", "discord-api-types": "^0.38.1", "fast-deep-equal": "^3.1.3", "ts-mixer": "^6.0.4", "tslib": "^2.6.3" } }, "sha512-F1WTABdd8/R9D1icJzajC4IuLyyS8f3rTOz66JsSI3pKvpCAtsMBweu8cyNYsIyvcrKAVn9EPK+Psoymq+XC0A=="],
"@discordjs/collection": ["@discordjs/collection@1.5.3", "", {}, "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ=="],
"@discordjs/formatters": ["@discordjs/formatters@0.6.1", "", { "dependencies": { "discord-api-types": "^0.38.1" } }, "sha512-5cnX+tASiPCqCWtFcFslxBVUaCetB0thvM/JyavhbXInP1HJIEU+Qv/zMrnuwSsX3yWH2lVXNJZeDK3EiP4HHg=="],
"@discordjs/rest": ["@discordjs/rest@2.5.1", "", { "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.1", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", "undici": "6.21.3" } }, "sha512-Tg9840IneBcbrAjcGaQzHUJWFNq1MMWZjTdjJ0WS/89IffaNKc++iOvffucPxQTF/gviO9+9r8kEPea1X5J2Dw=="],
"@discordjs/util": ["@discordjs/util@1.1.1", "", {}, "sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g=="],
"@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=="],
"@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
"@esbuild-kit/cjs-loader": ["@esbuild-kit/cjs-loader@2.4.4", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.2.3", "get-tsconfig": "^4.7.0" } }, "sha512-NfsJX4PdzhwSkfJukczyUiZGc7zNNWZcEAyqeISpDnn0PTfzMJR1aR8xAIPskBejIxBJbIgCCMzbaYa9SXepIg=="],
"@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "~0.18.20", "source-map-support": "^0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="],
"@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.19.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.19.12", "", { "os": "android", "cpu": "arm" }, "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.19.12", "", { "os": "android", "cpu": "arm64" }, "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.19.12", "", { "os": "android", "cpu": "x64" }, "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.19.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.19.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.19.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.19.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.19.12", "", { "os": "linux", "cpu": "arm" }, "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.19.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.19.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.19.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.19.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.19.12", "", { "os": "linux", "cpu": "x64" }, "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.19.12", "", { "os": "none", "cpu": "x64" }, "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.19.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.19.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.19.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.19.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.19.12", "", { "os": "win32", "cpu": "x64" }, "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA=="],
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.1.0" }, "os": "darwin", "cpu": "arm64" }, "sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg=="],
"@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.1.0" }, "os": "darwin", "cpu": "x64" }, "sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g=="],
"@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.1.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA=="],
"@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.1.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ=="],
"@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.1.0", "", { "os": "linux", "cpu": "arm" }, "sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA=="],
"@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.1.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew=="],
"@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.1.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ=="],
"@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.1.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA=="],
"@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.1.0", "", { "os": "linux", "cpu": "x64" }, "sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q=="],
"@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.1.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w=="],
"@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.1.0", "", { "os": "linux", "cpu": "x64" }, "sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A=="],
"@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.1.0" }, "os": "linux", "cpu": "arm" }, "sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ=="],
"@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.1.0" }, "os": "linux", "cpu": "arm64" }, "sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q=="],
"@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.1.0" }, "os": "linux", "cpu": "s390x" }, "sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw=="],
"@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.1.0" }, "os": "linux", "cpu": "x64" }, "sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ=="],
"@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.1.0" }, "os": "linux", "cpu": "arm64" }, "sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA=="],
"@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.1.0" }, "os": "linux", "cpu": "x64" }, "sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA=="],
"@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.2", "", { "dependencies": { "@emnapi/runtime": "^1.4.3" }, "cpu": "none" }, "sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ=="],
"@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ=="],
"@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw=="],
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.2", "", { "os": "win32", "cpu": "x64" }, "sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw=="],
"@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
"@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.3.0", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-zlayKCsIjYb7/IdfqxorK5+xUMyi4vOKcFy10wKJYc63NSdKI8mNME+uJqfatkPmOSMMUiojrL58IePKBm3gvQ=="],
"@napi-rs/canvas": ["@napi-rs/canvas@0.1.72", "", { "optionalDependencies": { "@napi-rs/canvas-android-arm64": "0.1.72", "@napi-rs/canvas-darwin-arm64": "0.1.72", "@napi-rs/canvas-darwin-x64": "0.1.72", "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.72", "@napi-rs/canvas-linux-arm64-gnu": "0.1.72", "@napi-rs/canvas-linux-arm64-musl": "0.1.72", "@napi-rs/canvas-linux-riscv64-gnu": "0.1.72", "@napi-rs/canvas-linux-x64-gnu": "0.1.72", "@napi-rs/canvas-linux-x64-musl": "0.1.72", "@napi-rs/canvas-win32-x64-msvc": "0.1.72" } }, "sha512-ypTJ/DXzsJbTU3o7qXFlWmZGgEbh42JWQl7v5/i+DJz/HURELcSnq9ler9e1ukqma70JzmCQcIseiE/Xs6sczw=="],
"@napi-rs/canvas-android-arm64": ["@napi-rs/canvas-android-arm64@0.1.72", "", { "os": "android", "cpu": "arm64" }, "sha512-OW99TDJEdfOhpJWQ7SXFsQi1BXd6UFuWM8AoQvJ0SQMHWY/iwuopmb1UqGV6Df9aM/SWxvCWBN/onjeCM8KVKQ=="],
"@napi-rs/canvas-darwin-arm64": ["@napi-rs/canvas-darwin-arm64@0.1.72", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gB8Pn/4GdS+B6P4HYuNqPGx8iQJ16Go1D6e5hIxfUbA/efupVGZ7e3OMGWGCUgF0vgbEPEF31sPzhcad4mdR5g=="],
"@napi-rs/canvas-darwin-x64": ["@napi-rs/canvas-darwin-x64@0.1.72", "", { "os": "darwin", "cpu": "x64" }, "sha512-x1zKtWVSnf+yLETHdSDAFJ1w6bctS/V2NP0wskTTBKkC+c/AmI2Dl+ZMIW11gF6rilBibrIzBeXJKPzV0GMWGA=="],
"@napi-rs/canvas-linux-arm-gnueabihf": ["@napi-rs/canvas-linux-arm-gnueabihf@0.1.72", "", { "os": "linux", "cpu": "arm" }, "sha512-Ef6HMF+TBS+lqBNpcUj2D17ODJrbgevXaVPtr2nQFCao5IvoEhVMdmVwWk5YiI+GcgbAkg5AF3LiU47RoSY5yg=="],
"@napi-rs/canvas-linux-arm64-gnu": ["@napi-rs/canvas-linux-arm64-gnu@0.1.72", "", { "os": "linux", "cpu": "arm64" }, "sha512-i1tWu+Li1Z6G4t+ckT38JwuB/cAAREV6H8VD3dip2yTYU+qnLz6kG4i+whm+SEQb1e4vk3xA1lKnjYx3jlOy8g=="],
"@napi-rs/canvas-linux-arm64-musl": ["@napi-rs/canvas-linux-arm64-musl@0.1.72", "", { "os": "linux", "cpu": "arm64" }, "sha512-Mu+2hHZAT9SdrjiRtCxMD/Unac8vqVxF/p+Tvjb5sN1NZkLGu+l7WIfrug8aeX150OwrYgAvsR4mhrm0BZvLxg=="],
"@napi-rs/canvas-linux-riscv64-gnu": ["@napi-rs/canvas-linux-riscv64-gnu@0.1.72", "", { "os": "linux", "cpu": "none" }, "sha512-xBPG/ImL58I4Ep6VM+sCrpwl8rE/8e7Dt9U7zzggNvYHrWD13vIF3q5L2/N9VxdBMh1pee6dBC/VcaXLYccZNQ=="],
"@napi-rs/canvas-linux-x64-gnu": ["@napi-rs/canvas-linux-x64-gnu@0.1.72", "", { "os": "linux", "cpu": "x64" }, "sha512-jkC8L+QovHpzQrw+Jm1IUqxgLV5QB1hJ1cR8iYzxNRd0TOF7YfxLaIGxvd/ReRi9r48JT6PL7z2IGT7TqK8T4w=="],
"@napi-rs/canvas-linux-x64-musl": ["@napi-rs/canvas-linux-x64-musl@0.1.72", "", { "os": "linux", "cpu": "x64" }, "sha512-PwPdPmHgJYnTMUr8Gff80eRVdpGjwrxueIqw+7v4aeFxbQjmQ+paa2xaGedFtkvdS2Dn5z8a0mVlrlbSfec+1Q=="],
"@napi-rs/canvas-win32-x64-msvc": ["@napi-rs/canvas-win32-x64-msvc@0.1.72", "", { "os": "win32", "cpu": "x64" }, "sha512-hZhXJZZ/2ZjkAoOtyGUs3Mx6jA4o9ESbc5bk+NKYO6thZRvRNA7rqvT9WF9pZK0xcRK5EyWRymv8fCzqmSVEzg=="],
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
"@prisma/client": ["@prisma/client@6.10.1", "", { "peerDependencies": { "prisma": "*", "typescript": ">=5.1.0" }, "optionalPeers": ["prisma", "typescript"] }, "sha512-Re4pMlcUsQsUTAYMK7EJ4Bw2kg3WfZAAlr8GjORJaK4VOP6LxRQUQ1TuLnxcF42XqGkWQ36q5CQF1yVadANQ6w=="],
"@prisma/config": ["@prisma/config@6.10.1", "", { "dependencies": { "jiti": "2.4.2" } }, "sha512-kz4/bnqrOrzWo8KzYguN0cden4CzLJJ+2VSpKtF8utHS3l1JS0Lhv6BLwpOX6X9yNreTbZQZwewb+/BMPDCIYQ=="],
"@prisma/debug": ["@prisma/debug@6.10.1", "", {}, "sha512-k2YT53cWxv9OLjW4zSYTZ6Z7j0gPfCzcr2Mj99qsuvlxr8WAKSZ2NcSR0zLf/mP4oxnYG842IMj3utTgcd7CaA=="],
"@prisma/engines": ["@prisma/engines@6.10.1", "", { "dependencies": { "@prisma/debug": "6.10.1", "@prisma/engines-version": "6.10.1-1.9b628578b3b7cae625e8c927178f15a170e74a9c", "@prisma/fetch-engine": "6.10.1", "@prisma/get-platform": "6.10.1" } }, "sha512-Q07P5rS2iPwk2IQr/rUQJ42tHjpPyFcbiH7PXZlV81Ryr9NYIgdxcUrwgVOWVm5T7ap02C0dNd1dpnNcSWig8A=="],
"@prisma/engines-version": ["@prisma/engines-version@6.10.1-1.9b628578b3b7cae625e8c927178f15a170e74a9c", "", {}, "sha512-ZJFTsEqapiTYVzXya6TUKYDFnSWCNegfUiG5ik9fleQva5Sk3DNyyUi7X1+0ZxWFHwHDr6BZV5Vm+iwP+LlciA=="],
"@prisma/fetch-engine": ["@prisma/fetch-engine@6.10.1", "", { "dependencies": { "@prisma/debug": "6.10.1", "@prisma/engines-version": "6.10.1-1.9b628578b3b7cae625e8c927178f15a170e74a9c", "@prisma/get-platform": "6.10.1" } }, "sha512-clmbG/Jgmrc/n6Y77QcBmAUlq9LrwI9Dbgy4pq5jeEARBpRCWJDJ7PWW1P8p0LfFU0i5fsyO7FqRzRB8mkdS4g=="],
"@prisma/get-platform": ["@prisma/get-platform@6.10.1", "", { "dependencies": { "@prisma/debug": "6.10.1" } }, "sha512-4CY5ndKylcsce9Mv+VWp5obbR2/86SHOLVV053pwIkhVtT9C9A83yqiqI/5kJM9T1v1u1qco/bYjDKycmei9HA=="],
"@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=="],
"@sapphire/snowflake": ["@sapphire/snowflake@3.5.3", "", {}, "sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ=="],
"@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="],
"@sern/cli": ["@sern/cli@1.4.0", "", { "dependencies": { "@esbuild-kit/cjs-loader": "^2.4.2", "@esbuild-kit/esm-loader": "^2.5.5", "colorette": "2.0.20", "commander": "11.0.0", "dotenv": "^16.3.1", "esbuild": "^0.19.1", "execa": "7.2.0", "find-up": "6.3.0", "glob": "^10.3.3", "ora": "6.3.1", "prompts": "2.4.2", "undici": "5.23.0" }, "bin": { "sern": "dist/index.js" } }, "sha512-IePGYYJvIVwNtnukblYxE2X7hiFivLa/p4UVaMi0XLpZ+Fa3BAdsSiBKRzLtBYWl8J2Se9StLSFwBYQW7ik+/Q=="],
"@sern/handler": ["@sern/handler@4.2.4", "", { "dependencies": { "@sern/ioc": "^1.1.2", "callsites": "^3.1.0", "cron": "^3.1.7", "deepmerge": "^4.3.1" } }, "sha512-8qnYSwH2x5zhp7YidtDxQZFaQrwYn+YITk4kWrvqOx6b9PVDKtdzkjXd4e7dnI0tdmGuVwJGk6eRl/RnGUVDqw=="],
"@sern/ioc": ["@sern/ioc@1.1.2", "", {}, "sha512-n84w7n5hB1dl8N6dfSbeYIo0QYORMS1bpG/P7J7GoMNTu8c28EYVZ8uGs3Md9GB09UseOKn3mfv1QBDtRsbb1g=="],
"@sern/publisher": ["@sern/publisher@1.1.2", "", {}, "sha512-1zh99JZykKUhqHhE75ZXfiLsBtf1WI+NnDCojv8UlpnGBEyzO8xyI1X7PNf6cPKRs4W9XqY3PqTJ+hrqzIsMkg=="],
"@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@4.0.0", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="],
"@types/bun": ["@types/bun@1.2.18", "", { "dependencies": { "bun-types": "1.2.18" } }, "sha512-Xf6RaWVheyemaThV0kUfaAUvCNokFr+bH8Jxp+tTZfx7dAPA8z9ePnP9S9+Vspzuxxx9JRAXhnyccRj3GyCMdQ=="],
"@types/luxon": ["@types/luxon@3.4.2", "", {}, "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA=="],
"@types/mongodb": ["@types/mongodb@4.0.7", "", { "dependencies": { "mongodb": "*" } }, "sha512-lPUYPpzA43baXqnd36cZ9xxorprybxXDzteVKCPAdp14ppHtFJHnXYvNpmBvtMUTb5fKXVv6sVbzo1LHkWhJlw=="],
"@types/node": ["@types/node@17.0.45", "", {}, "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw=="],
"@types/react": ["@types/react@19.1.8", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g=="],
"@types/webidl-conversions": ["@types/webidl-conversions@7.0.3", "", {}, "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA=="],
"@types/whatwg-url": ["@types/whatwg-url@11.0.5", "", { "dependencies": { "@types/webidl-conversions": "*" } }, "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ=="],
"@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
"@vladfrangu/async_event_emitter": ["@vladfrangu/async_event_emitter@2.4.6", "", {}, "sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA=="],
"ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
"ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
"bl": ["bl@5.1.0", "", { "dependencies": { "buffer": "^6.0.3", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ=="],
"boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="],
"brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"bson": ["bson@6.10.4", "", {}, "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng=="],
"buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
"bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="],
"busboy": ["busboy@1.6.0", "", { "dependencies": { "streamsearch": "^1.1.0" } }, "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA=="],
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
"chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
"cli-cursor": ["cli-cursor@4.0.0", "", { "dependencies": { "restore-cursor": "^4.0.0" } }, "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg=="],
"cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="],
"clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="],
"color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="],
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="],
"colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="],
"commander": ["commander@11.0.0", "", {}, "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ=="],
"cron": ["cron@3.5.0", "", { "dependencies": { "@types/luxon": "~3.4.0", "luxon": "~3.5.0" } }, "sha512-0eYZqCnapmxYcV06uktql93wNWdlTmmBFP2iYz+JPVcQqlyFYcn1lFuIk4R54pkOmE7mcldTAPZv6X5XA4Q46A=="],
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
"css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="],
"css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="],
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
"deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
"defaults": ["defaults@1.0.4", "", { "dependencies": { "clone": "^1.0.2" } }, "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A=="],
"detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="],
"discord-api-types": ["discord-api-types@0.38.13", "", {}, "sha512-FELWJRgLVQuR7Az8RhdEZE0k6QNjSW9PCUcU1iyP2Gke8HrJmnMceSS9pD93UM64s3tvZzJPajpPLjWZJylf4g=="],
"discord.js": ["discord.js@14.21.0", "", { "dependencies": { "@discordjs/builders": "^1.11.2", "@discordjs/collection": "1.5.3", "@discordjs/formatters": "^0.6.1", "@discordjs/rest": "^2.5.1", "@discordjs/util": "^1.1.1", "@discordjs/ws": "^1.2.3", "@sapphire/snowflake": "3.5.3", "discord-api-types": "^0.38.1", "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-U5w41cEmcnSfwKYlLv5RJjB8Joa+QJyRwIJz5i/eg+v2Qvv6EYpCRhN9I2Rlf0900LuqSDg8edakUATrDZQncQ=="],
"dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="],
"domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="],
"domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="],
"domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="],
"dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
"emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
"entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
"esbuild": ["esbuild@0.19.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.19.12", "@esbuild/android-arm": "0.19.12", "@esbuild/android-arm64": "0.19.12", "@esbuild/android-x64": "0.19.12", "@esbuild/darwin-arm64": "0.19.12", "@esbuild/darwin-x64": "0.19.12", "@esbuild/freebsd-arm64": "0.19.12", "@esbuild/freebsd-x64": "0.19.12", "@esbuild/linux-arm": "0.19.12", "@esbuild/linux-arm64": "0.19.12", "@esbuild/linux-ia32": "0.19.12", "@esbuild/linux-loong64": "0.19.12", "@esbuild/linux-mips64el": "0.19.12", "@esbuild/linux-ppc64": "0.19.12", "@esbuild/linux-riscv64": "0.19.12", "@esbuild/linux-s390x": "0.19.12", "@esbuild/linux-x64": "0.19.12", "@esbuild/netbsd-x64": "0.19.12", "@esbuild/openbsd-x64": "0.19.12", "@esbuild/sunos-x64": "0.19.12", "@esbuild/win32-arm64": "0.19.12", "@esbuild/win32-ia32": "0.19.12", "@esbuild/win32-x64": "0.19.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg=="],
"execa": ["execa@9.6.0", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.6", "figures": "^6.1.0", "get-stream": "^9.0.0", "human-signals": "^8.0.1", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", "pretty-ms": "^9.2.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "yoctocolors": "^2.1.1" } }, "sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw=="],
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
"figures": ["figures@6.1.0", "", { "dependencies": { "is-unicode-supported": "^2.0.0" } }, "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg=="],
"find-up": ["find-up@6.3.0", "", { "dependencies": { "locate-path": "^7.1.0", "path-exists": "^5.0.0" } }, "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw=="],
"foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
"get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="],
"get-tsconfig": ["get-tsconfig@4.10.1", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ=="],
"glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
"he": ["he@1.2.0", "", { "bin": { "he": "bin/he" } }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="],
"human-signals": ["human-signals@8.0.1", "", {}, "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ=="],
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
"is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="],
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
"is-interactive": ["is-interactive@2.0.0", "", {}, "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ=="],
"is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="],
"is-stream": ["is-stream@4.0.1", "", {}, "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A=="],
"is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="],
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
"jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
"jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
"kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
"locate-path": ["locate-path@7.2.0", "", { "dependencies": { "p-locate": "^6.0.0" } }, "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA=="],
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
"lodash.snakecase": ["lodash.snakecase@4.1.1", "", {}, "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw=="],
"log-symbols": ["log-symbols@5.1.0", "", { "dependencies": { "chalk": "^5.0.0", "is-unicode-supported": "^1.1.0" } }, "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA=="],
"lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
"luxon": ["luxon@3.5.0", "", {}, "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ=="],
"magic-bytes.js": ["magic-bytes.js@1.12.1", "", {}, "sha512-ThQLOhN86ZkJ7qemtVRGYM+gRgR8GEXNli9H/PMvpnZsE44Xfh3wx9kGJaldg314v85m+bFW6WBMaVHJc/c3zA=="],
"memory-pager": ["memory-pager@1.5.0", "", {}, "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg=="],
"merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="],
"mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="],
"minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
"mongodb": ["mongodb@6.17.0", "", { "dependencies": { "@mongodb-js/saslprep": "^1.1.9", "bson": "^6.10.4", "mongodb-connection-string-url": "^3.0.0" }, "peerDependencies": { "@aws-sdk/credential-providers": "^3.188.0", "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", "gcp-metadata": "^5.2.0", "kerberos": "^2.0.1", "mongodb-client-encryption": ">=6.0.0 <7", "snappy": "^7.2.2", "socks": "^2.7.1" }, "optionalPeers": ["@aws-sdk/credential-providers", "@mongodb-js/zstd", "gcp-metadata", "kerberos", "mongodb-client-encryption", "snappy", "socks"] }, "sha512-neerUzg/8U26cgruLysKEjJvoNSXhyID3RvzvdcpsIi2COYM3FS3o9nlH7fxFtefTb942dX3W9i37oPfCVj4wA=="],
"mongodb-connection-string-url": ["mongodb-connection-string-url@3.0.2", "", { "dependencies": { "@types/whatwg-url": "^11.0.2", "whatwg-url": "^14.1.0 || ^13.0.0" } }, "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA=="],
"node-html-parser": ["node-html-parser@7.0.1", "", { "dependencies": { "css-select": "^5.1.0", "he": "1.2.0" } }, "sha512-KGtmPY2kS0thCWGK0VuPyOS+pBKhhe8gXztzA2ilAOhbUbxa9homF1bOyKvhGzMLXUoRds9IOmr/v5lr/lqNmA=="],
"npm-run-path": ["npm-run-path@6.0.0", "", { "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA=="],
"nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="],
"onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="],
"openai": ["openai@5.10.2", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.23.8" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-n+vi74LzHtvlKcDPn9aApgELGiu5CwhaLG40zxLTlFQdoSJCLACORIPC2uVQ3JEYAbqapM+XyRKFy2Thej7bIw=="],
"ora": ["ora@6.3.1", "", { "dependencies": { "chalk": "^5.0.0", "cli-cursor": "^4.0.0", "cli-spinners": "^2.6.1", "is-interactive": "^2.0.0", "is-unicode-supported": "^1.1.0", "log-symbols": "^5.1.0", "stdin-discarder": "^0.1.0", "strip-ansi": "^7.0.1", "wcwidth": "^1.0.1" } }, "sha512-ERAyNnZOfqM+Ao3RAvIXkYh5joP220yf59gVe2X/cI6SiCxIdi4c9HZKZD8R6q/RDXEje1THBju6iExiSsgJaQ=="],
"p-limit": ["p-limit@4.0.0", "", { "dependencies": { "yocto-queue": "^1.0.0" } }, "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ=="],
"p-locate": ["p-locate@6.0.0", "", { "dependencies": { "p-limit": "^4.0.0" } }, "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw=="],
"package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
"parse-ms": ["parse-ms@4.0.0", "", {}, "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw=="],
"path-exists": ["path-exists@5.0.0", "", {}, "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="],
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
"path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
"pretty-ms": ["pretty-ms@9.2.0", "", { "dependencies": { "parse-ms": "^4.0.0" } }, "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg=="],
"prisma": ["prisma@6.10.1", "", { "dependencies": { "@prisma/config": "6.10.1", "@prisma/engines": "6.10.1" }, "peerDependencies": { "typescript": ">=5.1.0" }, "optionalPeers": ["typescript"], "bin": { "prisma": "build/index.js" } }, "sha512-khhlC/G49E4+uyA3T3H5PRBut486HD2bDqE2+rvkU0pwk9IAqGFacLFUyIx9Uw+W2eCtf6XGwsp+/strUwMNPw=="],
"prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="],
"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=="],
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
"restore-cursor": ["restore-cursor@4.0.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg=="],
"rockpaperscissors-checker": ["rockpaperscissors-checker@1.2.0", "", {}, "sha512-JfndRzDvMo1st+iK9dKZIEToFDouc+53+whmVFs+zyBOp0zv/sMNY9hUZI5J7ulygmW1fI6QmvRyXmfpN9Sh8Q=="],
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
"semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
"sharp": ["sharp@0.34.2", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.4", "semver": "^7.7.2" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.2", "@img/sharp-darwin-x64": "0.34.2", "@img/sharp-libvips-darwin-arm64": "1.1.0", "@img/sharp-libvips-darwin-x64": "1.1.0", "@img/sharp-libvips-linux-arm": "1.1.0", "@img/sharp-libvips-linux-arm64": "1.1.0", "@img/sharp-libvips-linux-ppc64": "1.1.0", "@img/sharp-libvips-linux-s390x": "1.1.0", "@img/sharp-libvips-linux-x64": "1.1.0", "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", "@img/sharp-libvips-linuxmusl-x64": "1.1.0", "@img/sharp-linux-arm": "0.34.2", "@img/sharp-linux-arm64": "0.34.2", "@img/sharp-linux-s390x": "0.34.2", "@img/sharp-linux-x64": "0.34.2", "@img/sharp-linuxmusl-arm64": "0.34.2", "@img/sharp-linuxmusl-x64": "0.34.2", "@img/sharp-wasm32": "0.34.2", "@img/sharp-win32-arm64": "0.34.2", "@img/sharp-win32-ia32": "0.34.2", "@img/sharp-win32-x64": "0.34.2" } }, "sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg=="],
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
"signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
"simple-swizzle": ["simple-swizzle@0.2.2", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg=="],
"sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="],
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
"source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="],
"sparse-bitfield": ["sparse-bitfield@3.0.3", "", { "dependencies": { "memory-pager": "^1.0.2" } }, "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ=="],
"stdin-discarder": ["stdin-discarder@0.1.0", "", { "dependencies": { "bl": "^5.0.0" } }, "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ=="],
"streamsearch": ["streamsearch@1.1.0", "", {}, "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="],
"string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
"string-width-cjs": ["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=="],
"string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
"strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
"strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"strip-final-newline": ["strip-final-newline@4.0.0", "", {}, "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw=="],
"tr46": ["tr46@5.1.1", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw=="],
"ts-mixer": ["ts-mixer@6.0.4", "", {}, "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA=="],
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
"undici": ["undici@5.23.0", "", { "dependencies": { "busboy": "^1.6.0" } }, "sha512-1D7w+fvRsqlQ9GscLBwcAJinqcZGHUKjbOmXdlE/v8BvEGXjeWAax+341q44EuTcHXXnfyKNbKRq4Lg7OzhMmg=="],
"unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="],
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
"wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="],
"webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="],
"whatwg-url": ["whatwg-url@14.2.0", "", { "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" } }, "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw=="],
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
"wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
"wrap-ansi-cjs": ["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=="],
"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=="],
"yocto-queue": ["yocto-queue@1.2.1", "", {}, "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg=="],
"yoctocolors": ["yoctocolors@2.1.1", "", {}, "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ=="],
"@discordjs/rest/@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="],
"@discordjs/rest/undici": ["undici@6.21.3", "", {}, "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw=="],
"@discordjs/ws/@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="],
"@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="],
"@sern/cli/execa": ["execa@7.2.0", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.1", "human-signals": "^4.3.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^3.0.7", "strip-final-newline": "^3.0.0" } }, "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA=="],
"discord.js/undici": ["undici@6.21.3", "", {}, "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw=="],
"figures/is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="],
"npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
"restore-cursor/onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
"restore-cursor/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
"string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"wrap-ansi-cjs/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=="],
"wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="],
"@sern/cli/execa/get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="],
"@sern/cli/execa/human-signals": ["human-signals@4.3.1", "", {}, "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ=="],
"@sern/cli/execa/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="],
"@sern/cli/execa/npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="],
"@sern/cli/execa/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
"@sern/cli/execa/strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="],
"restore-cursor/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
"string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"@sern/cli/execa/npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
}
}

View File

@@ -1,36 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import { ownerOnly } from "#plugins";
import { ApplicationCommandOptionType } from "discord.js";
/*
import { publish } from "#plugins";
import { ownerOnly } from "#plugins"
*/
export default commandModule({
name: '8ball',
type: CommandType.Slash,
plugins: [publish()],
description: 'Preguntale a la 8-ball cosas.',
//alias : [],
options: [{
name: "pregunta",
description: "Escribe lo que le quieres preguntar.",
type: ApplicationCommandOptionType.String,
required: true
}],
execute: async (ctx, options) => {
// yes, the question argument is never used. There is no reason to use it in the code.
var eightballwords = [
'Probablemente',
'Sí',
'No',
'Dudable',
'Como lo veo, todo indica a que sí',
'A lo mejor',
'No cuentes con ello',
'Buena suerte'
]
await ctx.reply({content: `La bola tiene respuesta: ${eightballwords[Math.floor(Math.random() * eightballwords.length)]}.`, ephemeral: true})
},
});

View File

@@ -1,96 +0,0 @@
import { commandModule, CommandType } from '@sern/handler';
import {
ApplicationCommandOptionType,
AttachmentBuilder,
AutocompleteInteraction,
EmbedBuilder,
} from 'discord.js';
import { publish } from '#plugins';
const choices = [
'XaviXE',
'Paula',
'William',
'Espejito2500',
'Wheelook',
'MarioCabrera',
'Paticama',
'Vinci',
'SrIzan',
'ItsAdrian',
'ByHGT',
'Irene',
'Boniato64',
'Tormentarosa',
'H',
'SpRaY',
];
export default commandModule({
name: 'a',
type: CommandType.Slash,
plugins: [publish()],
description: 'A',
//alias : [],
options: [
{
name: 'usuario',
description: 'Usuario que debería aparecer',
type: ApplicationCommandOptionType.String,
autocomplete: true,
command: {
onEvent: [],
async execute(ctx: AutocompleteInteraction) {
const focusedValue = ctx.options.getFocused();
const filtered = choices.filter((choice) =>
choice.startsWith(focusedValue)
);
await ctx.respond(
filtered.map((choice) => ({ name: choice, value: choice }))
);
},
},
},
],
execute: async (ctx, options) => {
const option = ctx.interaction.options.getString('usuario');
if (!option) {
const imagesArray = [
'./images/a/XaviXE.png',
'./images/a/Paula.png',
'./images/a/William.png',
'./images/a/Espejito2500.png',
'./images/a/Wheelook.png',
'./images/a/MarioCabrera.png',
'./images/a/Paticama.png',
'./images/a/Vinci.png',
'./images/a/SrIzan.png',
'./images/a/ItsAdrian.png',
'./images/a/ByHGT.png',
'./images/a/Irene.png',
'./images/a/Boniato64.png',
'./images/a/Tormentarosa.png',
'./images/a/H.png',
'./images/a/SpRaY.png',
];
const images =
imagesArray[Math.floor(Math.random() * imagesArray.length)];
await ctx.reply({ content: 'A', files: [images] });
} else {
if (choices.indexOf(options[1].getString('usuario', true)) > -1) {
const attachmentbuilder = new AttachmentBuilder(
`./images/a/${options[1].getString('usuario', true)}.png`
);
await ctx.reply({ content: 'A', files: [attachmentbuilder] });
} else {
const embed = new EmbedBuilder()
.setTitle('A no encontrado!')
.setDescription(
`Qué raro, no se ha encontrado ese /a...\nPorqué no pruebas a poner uno del autocompletado?`
)
.setColor('Red');
await ctx.reply({ embeds: [embed], ephemeral: true });
}
}
},
});

View File

@@ -1,192 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import axios from "axios";
import { ActionRowBuilder, ApplicationCommandOptionType, ButtonBuilder, ButtonStyle, ComponentType, EmbedBuilder } from "discord.js";
import { publish } from "#plugins";
/*
import { publish } from "#plugins";
import { ownerOnly } from "#plugins"
*/
export default commandModule({
name: 'animal',
type: CommandType.Slash,
plugins: [publish()],
description: 'Enseña un animal',
//alias : [],
options: [
{
name: 'gato',
description: 'Enseña un gato',
type: ApplicationCommandOptionType.Subcommand
},
{
name: 'capybara',
description: 'Enseña un capybara',
type: ApplicationCommandOptionType.Subcommand
},
{
name: 'zorro',
description: 'Enseña un zorro',
type: ApplicationCommandOptionType.Subcommand
},
{
name: 'perro',
description: 'what the dog doin',
type: ApplicationCommandOptionType.Subcommand
},
{
name: 'mapache',
description: 'Enseña un mapache',
type: ApplicationCommandOptionType.Subcommand
}
],
execute: async (ctx, options) => {
switch (options[1].getSubcommand()) {
case 'gato': {
const request = await axios.get(`https://api.thecatapi.com/v1/images/search?api_key=${process.env.CATAPI}`).then(res => res.data)
const embed = new EmbedBuilder()
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
.setColor("Random")
.setImage(request[0].url)
.setFooter({text: `ID: ${request[0].id}`})
.setTitle('Gato')
const row = new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setCustomId("cat-upvote")
.setEmoji("⬆️")
.setStyle(ButtonStyle.Success),
new ButtonBuilder()
.setCustomId("cat-downvote")
.setEmoji("⬇️")
.setStyle(ButtonStyle.Danger),
)
const rowdisabled = new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setCustomId("cat-upvote")
.setEmoji("⬆️")
.setStyle(ButtonStyle.Success)
.setDisabled(true),
new ButtonBuilder()
.setCustomId("cat-downvote")
.setEmoji("⬇️")
.setStyle(ButtonStyle.Danger)
.setDisabled(true),
)
const message = await ctx.reply({embeds: [embed], components: [row]})
const collector = message.createMessageComponentCollector({time: 30000, componentType: ComponentType.Button})
collector.on('collect', async (i) => {
await i.deferReply({ephemeral: true})
if (i.customId === "cat-upvote") {
await axios.post(`https://api.thecatapi.com/v1/votes?api_key=${process.env.CATAPI}`, {
"image_id": request[0].id,
"sub_id": i.user.id,
"value": 1
})
i.editReply({content: "Has votado positivamente al gato con ID " + "`" + request[0].id + "`"})
}
if (i.customId === "cat-downvote") {
await axios.post(`https://api.thecatapi.com/v1/votes?api_key=${process.env.CATAPI}`, {
"image_id": request[0].id,
"sub_id": i.user.id,
"value": -1
})
i.editReply({content: "Has votado negativamente al gato con ID " + "`" + request[0].id + "`"})
}
})
collector.on('end', async (i) => {
await message.edit({components: [rowdisabled]})
})
}
case 'capybara': {
const request = await axios('https://api.capybara-api.xyz/v1/image/random').then(res => res.data)
const requestfacts = await axios('https://api.capybara-api.xyz/v1/facts/random').then(res => res.data)
const embed = new EmbedBuilder()
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
.setTitle('Capybara')
.setDescription(`Fun fact: ${requestfacts.fact}`)
.setColor('Random')
.setImage(request.image_urls.medium)
.setFooter({text: `ID: ${request.id}`})
await ctx.interaction.reply({embeds: [embed]})
}
case 'zorro': {
const request = await axios('https://randomfox.ca/floof/').then(res => res.data)
const embed = new EmbedBuilder()
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
.setTitle('Zorro')
.setColor('Random')
.setImage(request.image)
await ctx.interaction.reply({embeds: [embed]})
}
case 'perro': {
const request = await axios.get(`https://api.thedogapi.com/v1/images/search?api_key=${process.env.DOGAPI}`).then(res => res.data)
const embed = new EmbedBuilder()
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
.setColor("Random")
.setImage(request[0].url)
.setFooter({text: `ID: ${request[0].id}`})
.setTitle('Perro')
const row = new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setCustomId("dog-upvote")
.setEmoji("⬆️")
.setStyle(ButtonStyle.Success),
new ButtonBuilder()
.setCustomId("dog-downvote")
.setEmoji("⬇️")
.setStyle(ButtonStyle.Danger),
)
const rowdisabled = new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setCustomId("dog-upvote")
.setEmoji("⬆️")
.setStyle(ButtonStyle.Success)
.setDisabled(true),
new ButtonBuilder()
.setCustomId("dog-downvote")
.setEmoji("⬇️")
.setStyle(ButtonStyle.Danger)
.setDisabled(true),
)
const message = await ctx.reply({embeds: [embed], components: [row]})
const collector = message.createMessageComponentCollector({time: 30000, componentType: ComponentType.Button})
collector.on('collect', async (i) => {
await i.deferReply({ephemeral: true})
if (i.customId === "dog-upvote") {
await axios.post(`https://api.thedogapi.com/v1/votes?api_key=${process.env.DOGAPI}`, {
"image_id": request[0].id,
"sub_id": i.user.id,
"value": 1
})
i.editReply({content: "Has votado positivamente al gato con ID " + "`" + request[0].id + "`"})
}
if (i.customId === "dog-downvote") {
await axios.post(`https://api.thedogapi.com/v1/votes?api_key=${process.env.DOGAPI}`, {
"image_id": request[0].id,
"sub_id": i.user.id,
"value": -1
})
i.editReply({content: "Has votado negativamente al gato con ID " + "`" + request[0].id + "`"})
}
})
collector.on('end', async () => {
await message.edit({components: [rowdisabled]})
})
}
case 'mapache': {
const request = await axios('https://some-random-api.ml/animal/raccoon').then(res => res.data)
const embed = new EmbedBuilder()
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
.setTitle('Mapache')
.setDescription(`Fun fact: ${request.fact}`)
.setColor('Random')
.setImage(request.image)
await ctx.interaction.reply({embeds: [embed]})
}
}
},
});

View File

@@ -1,168 +0,0 @@
import { commandModule, CommandType } from '@sern/handler';
import { publish } from '#plugins';
import { ANIME } from '@consumet/extensions';
import {
ActionRowBuilder,
ApplicationCommandOptionType,
ButtonBuilder,
ButtonStyle,
ComponentType,
EmbedBuilder,
} from 'discord.js';
/*
import { publish } from "#plugins";
import { ownerOnly } from "#plugins"
*/
export default commandModule({
type: CommandType.Slash,
plugins: [publish()],
description: 'busca cosas en gogoanime',
//alias : [],
options: [
{
name: 'buscar',
description: 'Busca un anime',
type: ApplicationCommandOptionType.Subcommand,
options: [
{
name: 'palabra-clave',
description: 'La palabra clave',
type: ApplicationCommandOptionType.String,
required: true,
},
],
},
{
name: 'capitulo',
description: 'Mira los links de directo de cualquier capítulo (con su ID)',
type: ApplicationCommandOptionType.Subcommand,
options: [
{
name: 'id-serie',
description: 'El ID de la serie (búscalo primero)',
type: ApplicationCommandOptionType.String,
required: true
},
{
name: 'id-capitulo',
description: 'El ID del capítulo (usa el autocompletado)',
type: ApplicationCommandOptionType.String,
required: true,
autocomplete: true,
command: {
onEvent: [],
execute: async (autocomplete) => {
try {
const focusedOption = autocomplete.options.getFocused();
const gogoanime = new ANIME.Gogoanime();
const serieOption = autocomplete.options.getString('id-serie', true)
const fetch = await gogoanime.fetchAnimeInfo(serieOption)
let choices = fetch.episodes!.filter((choice) => choice.number.toString().startsWith(focusedOption))
choices = choices.slice(0, 25)
await autocomplete.respond(
choices.map((choice) => ({
name: choice.number.toString(),
value: choice.id.toString(),
}))
)
} catch {
await autocomplete.respond([{name: 'Algo malo ha ocurrido! Asegúrate que hayas puesto el ID correctamente', value: 'error'}])
}
}
}
}
],
},
{
name: 'info',
description: 'INGLÉS: Consigue información sobre alguna serie con su ID.',
type: ApplicationCommandOptionType.Subcommand,
options: [
{
name: 'id',
description: 'El nombre de la serie',
type: ApplicationCommandOptionType.String,
required: true
}
]
}
],
execute: async (ctx, options) => {
const gogoanime = new ANIME.Gogoanime();
const doubleslashregex = new RegExp('(?<!:)\/\/+')
switch (options[1].getSubcommand()) {
case 'buscar': {
await ctx.interaction.deferReply()
const option = options[1].getString('palabra-clave', true);
const search = await gogoanime.search(option);
const editedarray = await Promise.all(
search.results
.map((results) => {
return `[${results.title}](<${results.url!.replace(doubleslashregex, '/')}>)`;
})
.slice(0, 5)
);
const editedarrayids = await Promise.all(
search.results
.map((results) => {
return `[${results.id}](<${results.url!.replace(doubleslashregex, '/')}>)`;
})
.slice(0, 5)
);
const button = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder()
.setCustomId('gogoanime-search-toid')
.setLabel('Cambiar a ID')
.setStyle(ButtonStyle.Secondary)
);
if (editedarray.length === 0) return await ctx.interaction.editReply({content: 'No se ha encontrado nada con ese resultado de búsqueda, prueba a ser más general o concreto idk'})
const message = await ctx.interaction.editReply({
content: `Resultados de la búsqueda \`${option}\`:\n${editedarray.join('\n')}`,
components: [button],
});
const collector = message.createMessageComponentCollector({max: 1, componentType: ComponentType.Button, time: 30000})
collector.on('collect', async (i) => {
if (i.customId !== 'gogoanime-search-toid') return;
await ctx.interaction.editReply({
content: `Resultados de la búsqueda \`${option}\` (modo ID):\n${editedarrayids.join('\n')}`,
components: []
})
await i.deferUpdate()
})
} break;
case 'capitulo': {
const selepisode = options[1].getString('id-capitulo', true)
try {
const search = await gogoanime.fetchEpisodeServers(selepisode)
const arrayed = await Promise.all(search.map((server) => `[${server.name}](<${server.url!.replace(doubleslashregex, '/')}>)`))
await ctx.reply({content: `Todos los servidores de \`${selepisode}\` (Vinci no se hace cargo de los enlaces):\n${arrayed.join('\n')}`})
} catch {
await ctx.reply({content: 'Ha ocurrido un error! Asegúrate que hayas seleccionado bien un capítulo.'})
}
} break;
case 'info': {
try {
const option = options[1].getString('id', true)
const info = await gogoanime.fetchAnimeInfo(option)
const embed = new EmbedBuilder()
.setColor('Random')
.setTitle(`${info.title}`)
.setURL(info.url!.replace(doubleslashregex, '/'))
.setThumbnail(info.image!)
.setFields(
{name: 'Géneros', value: `${info.genres!.join(', ')}`},
{name: 'Fecha de salida', value: `${info.releaseDate!}`, inline: true},
{name: 'Capítulos totales', value: `${info.totalEpisodes!}`, inline: true},
{name: '\u200B', value: '\u200B', inline: true},
{name: 'Tipo', value: `${info.type!}`, inline: true},
)
await ctx.reply({embeds: [embed]})
} catch {
await ctx.reply({content: 'Algo malo ha ocurrido, asegúrate que hayas escrito el ID correctamente\nTip: Usa el comando de buscar y conviértelos a ID.'})
}
} break;
}
},
});

View File

@@ -1,15 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import axios from "axios";
import { publish } from "#plugins";
export default commandModule({
name: 'chiste',
type: CommandType.Slash,
plugins: [publish()],
description: 'Enseña un chiste en inglés.',
execute: async (ctx, args) => {
const jokeJSON = await axios(
'https://v2.jokeapi.dev/joke/Programming,Miscellaneous,Spooky,Christmas?blacklistFlags=nsfw,religious,racist,sexist,explicit'
).then((res) => res.data);
ctx.reply({content: `${jokeJSON.joke || jokeJSON.setup}\n${jokeJSON.delivery || ""}`})
}})

View File

@@ -1,162 +0,0 @@
import { commandModule, CommandType } from '@sern/handler';
import { publish } from '#plugins';
import FormData from 'form-data';
import {
ActionRowBuilder,
ApplicationCommandOptionType,
AttachmentBuilder,
ButtonBuilder,
ButtonStyle,
} from 'discord.js';
import axios from 'axios';
import https from 'node:https'
/*
import { publish } from "#plugins";
import { ownerOnly } from "#plugins"
*/
export default commandModule({
type: CommandType.Slash,
plugins: [publish()],
//alias : [],
description: 'no one will read this (i hope)',
options: [
{
name: 'heartlocket',
description: 'El corazón con una imagen que todos conocemos',
type: ApplicationCommandOptionType.Subcommand,
options: [
{
name: 'imagen',
description: 'Imagen (jpg o png)',
type: ApplicationCommandOptionType.Attachment,
required: true,
},
{
name: 'texto',
description: 'El texto que poner',
type: ApplicationCommandOptionType.String,
},
],
},
],
execute: async (ctx, options) => {
await ctx.interaction.deferReply();
switch (options[1].getSubcommand()) {
case 'heartlocket':
{
try {
// get all options
const text = options[1].getString('texto');
const image = options[1].getAttachment('imagen', true);
// check file extension of attachment
if (
!image.contentType!.includes('image/png') &&
!image.contentType!.includes('image/jpeg')
)
return await ctx.interaction.editReply({
content:
'Tienes que usar una imagen con extensión `.png` o `.jpg`!',
});
// save in a const the content type
let fileExtension: string;
if (image.contentType!.includes('image/png')) {
fileExtension = 'png';
} else if (image.contentType!.includes('image/jpeg')) {
fileExtension = 'jpg';
} else {
fileExtension =
'this shouldnt be seen, but typescript is sometimes an idiot and it needs an else so it doesnt cry';
}
// upload to tmpfiles so it can be then uploaded to
const formDataTemp = new FormData();
const imageBinaryTemp = await axios
.get(image.url, { responseType: 'arraybuffer' })
.then((res) => res.data);
const bufferTemp = Buffer.from(imageBinaryTemp, 'binary');
formDataTemp.append('file', bufferTemp, `image.${fileExtension}`);
const tempupload = await axios
.post(
`https://tmpfiles.org/api/v1/upload`,
formDataTemp,
)
.then((res) => res.data);
// compress the image
const compress = await axios.get(`https://api.resmush.it/ws.php?img=${(tempupload.data.url as string).replace('https://tmpfiles.org/', 'https://tmpfiles.org/dl/')}&qlty=80`, {
httpsAgent: new https.Agent({ rejectUnauthorized: false })
}).then(res => res.data)
// convert image to a binary so it can be sent to the MakeSweet API.
const formData = new FormData();
const imageBinary = await axios
.get((compress.dest as string).replace(/\\\//g, '/'), { responseType: 'arraybuffer' })
.then((res) => res.data);
const buffer = Buffer.from(imageBinary, 'binary');
formData.append('images[]', buffer, `image.${fileExtension}`);
// make the request to the actual API, but first check if there's text.
let request: any;
if (text) {
request = await axios
.post(
`https://api.makesweet.com/make/heart-locket?text=${text}`,
formData,
{
headers: {
Authorization: process.env.MAKESWEET!,
},
responseType: 'arraybuffer',
}
)
.then((res) => res.data);
} else {
request = await axios
.post(`https://api.makesweet.com/make/heart-locket`, formData, {
headers: {
Authorization: process.env.MAKESWEET!,
},
responseType: 'arraybuffer',
})
.then((res) => res.data);
}
// make an attachment with the data that the MakeSweet API returned
const attachment = new AttachmentBuilder(request, {
name: 'makesweet.gif',
});
// finally, send the message
const message = await ctx.interaction.editReply({
content: 'Tu GIF está listo! 🎉',
files: [attachment],
});
// make an image link button
const button = new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setLabel('Enlace al GIF')
.setEmoji('📲')
.setURL(`https://api.srizan.dev/misc/download?url=${message.attachments.first()!.url}&type=gif`)
.setStyle(ButtonStyle.Link)
);
await ctx.interaction.editReply({
content: 'Tu GIF está listo! 🎉',
files: [attachment],
components: [button]
});
} catch (e) {
await ctx.interaction.editReply({
content: `ERROR: He intentado comprimir la imagen, pero no ha sido suficiente. Intenta usar una imagen menos pesada (1mb o menos)\nSi no es eso, probablemente ha ocurrido un error del que no tengo conocimiento.`,
});
}
}
break;
}
},
});

View File

@@ -1,59 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import { ownerOnly } from "#plugins";
import Canvas from '@napi-rs/canvas';
import { ApplicationCommandOptionType, AttachmentBuilder } from 'discord.js';
/*
import { publish } from "#plugins";
import { ownerOnly } from "#plugins"
*/
export default commandModule({
type: CommandType.Slash,
plugins: [publish()],
// , '928018226330337280'
description: 'Añade a una imagen de megamind "No ...?"',
//alias : [],
options: [
{
name: 'texto',
description: 'El texto SIN "No" ni "?".',
type: ApplicationCommandOptionType.String,
required: true
}
],
execute: async (ctx, options) => {
const option = options[1].getString('texto', true)
await ctx.reply({content: 'Cargando...'})
const before = performance.now()
const canvas = Canvas.createCanvas(535, 540)
const context = canvas.getContext('2d')
const background = await Canvas.loadImage('./images/megamind/megamind.png')
context.drawImage(background, 0, 0, canvas.width, canvas.height)
const text = `No ${option}?`
let fontsize = 60
do {
fontsize--;
context.font = fontsize + "px Impact";
} while (context.measureText(text).width > canvas.width)
context.fillStyle = 'white'
context.textAlign = 'center'
context.textBaseline = 'middle'
context.fillText(text, canvas.width / 2, canvas.height - 510)
const encode = await canvas.encode('png')
const after = performance.now()
const attachment = new AttachmentBuilder(encode, { name: 'megamind.png' });
await ctx.interaction.editReply({
content: `Aquí está tu megamind:\nLa generación de imagen ha tardado \`${(after - before).toFixed(2)}ms\`.`,
files: [attachment]
})
},
});

View File

@@ -1,113 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { ActionRowBuilder, ApplicationCommandOptionType, ButtonBuilder, ButtonStyle, ComponentType, EmbedBuilder, GuildMember } from "discord.js";
import { publish } from "#plugins";
import rockpaperscissors from "rockpaperscissors-checker";
export default commandModule({
name: 'rps',
type: CommandType.Slash,
plugins: [publish()],
description: 'Juega piedra papel tijeras con los panas',
//alias : [],
options: [
{
name: 'usuario',
description: 'El usuario con el que enfrentarse',
type: ApplicationCommandOptionType.User,
required: true
}
],
execute: async (ctx, options) => {
// also the code is mine, I didn't steal from anyone
let player1, player2, winner, bothResponded
const option = options[1].getMember('usuario') as GuildMember
if (ctx.user.id === option.id) {
return await ctx.reply({content: `no puedes jugar contigo mismo 💀`, ephemeral: true})
} else if (option.user.bot) {
return await ctx.reply({content: `no puedes seleccionar a un bot.`, ephemeral: true})
}
const waitingEmbed = new EmbedBuilder()
.setColor('Red')
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
.setTitle(`Piedra, papel o tijera? <:PauseChamp:1030169623070519388>`)
.setDescription(`Esperando a que ambos jugadores eligan...\nJugador 1: ${ctx.user}\nJugador 2: ${option}`)
.setFooter({text: `Hay un máximo de 30 segundos para elegir.`})
const winEmbed = new EmbedBuilder()
.setColor('Green')
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
.setFooter({text: `Gracias por jugar!`})
const tieEmbed = new EmbedBuilder()
.setColor('Yellow')
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
.setTitle(`Ha habido un empate <:Sadge:1015764348385382451>`)
.setDescription(`Qué sadge, ha habido un empate...`)
.setFooter({text: `Volvemos a intentarlo?`})
const timeUpEmbed = new EmbedBuilder()
.setColor('Red')
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
.setTitle(`Se acabó!`)
.setDescription(`Uno de los dos jugadores no han respondido en los 30 segundos, así que se acabó la partida!`)
.setFooter({text: `Volvemos a intentarlo?`})
const buttons = ["Piedra", "Papel", "Tijera"].map(choice => {
return new ButtonBuilder()
.setLabel(choice)
.setCustomId(`rps-${choice.toLowerCase()}`)
.setStyle(ButtonStyle.Secondary)
})
const row = new ActionRowBuilder<ButtonBuilder>();
const message = await ctx.interaction.reply({content: `${option}, te han retado a Piedra Papel o Tijera!`, embeds: [waitingEmbed], fetchReply: true, components: [row.setComponents(buttons)]})
const collector = message.createMessageComponentCollector({time: 30_000, componentType: ComponentType.Button, filter: (i) => [ctx.user.id, option.id].includes(i.user.id),})
collector.on('collect', async (i) => {
await i.deferReply({ephemeral: true})
if (i.customId === "rps-piedra") {
if (i.user.id === ctx.user.id) {
player1 = 1
await i.editReply({content: `Se ha respondido **piedra** correctamente, buena suerte!\n[Volver al mensaje](${message.url})`})
} else if (i.user.id === option.id) {
player2 = 1
await i.editReply({content: `Se ha respondido **piedra** correctamente, buena suerte!\n[Volver al mensaje](${message.url})`})
}
} else if (i.customId === "rps-papel") {
if (i.user.id === ctx.user.id) {
player1 = 2
await i.editReply({content: `Se ha respondido **papel** correctamente, buena suerte!\n[Volver al mensaje](${message.url})`})
} else if (i.user.id === option.id) {
player2 = 2
await i.editReply({content: `Se ha respondido **papel** correctamente, buena suerte!\n[Volver al mensaje](${message.url})`})
}
} else if (i.customId === "rps-tijera") {
if (i.user.id === ctx.user.id) {
player1 = 3
await i.editReply({content: `Se ha respondido **tijera** correctamente, buena suerte!\n[Volver al mensaje](${message.url})`})
} else if (i.user.id === option.id) {
player2 = 3
await i.editReply({content: `Se ha respondido **tijera** correctamente, buena suerte!\n[Volver al mensaje](${message.url})`})
}
}
if (player1 && player2) {
const checker = rockpaperscissors(player1, player2)
bothResponded = true
if (checker === "player1") {
winner = ctx.user.username
const setDescription = winEmbed.setDescription(`Tenemos resultados!\n**${winner}** ha ganado.`).setTitle(`Ha ganado ${winner}! <:Pog:1030169609178976346>`)
await message.edit({embeds: [setDescription], components: [], content: ``})
message.react('<:Pog:1030169609178976346>')
} else if (checker === "player2") {
winner = option.user.username
const setDescription = winEmbed.setDescription(`Tenemos resultados!\n**${winner}** ha ganado.`).setTitle(`Ha ganado ${winner}! <:Pog:1030169609178976346>`)
await message.edit({embeds: [setDescription], components: [], content: ``})
message.react('<:Pog:1030169609178976346>')
} else if (checker === "tie") {
await message.edit({embeds: [tieEmbed], components: [], content: ``})
}
}
})
collector.on('ignore', async (i) => {
await i.reply({content: 'No estás jugando!', ephemeral: true})
})
collector.on('end', async () => {
if (bothResponded) return;
await message.edit({embeds: [timeUpEmbed], components: [], content: ``})
})
},
});

View File

@@ -1,24 +0,0 @@
import TicTacToe from 'discord-tictactoe';
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import { ownerOnly } from "#plugins";
import { ApplicationCommandOptionType } from "discord.js";
const game = new TicTacToe({language: 'en'})
export default commandModule({
name: 'tictactoe',
type: CommandType.Slash,
plugins: [publish()],
description: 'tres en raya',
//alias : [],
options: [
{
name: "opponent",
description: "opponent",
type: ApplicationCommandOptionType.User
}
],
execute: async (ctx, options) => {
await game.handleInteraction(ctx.interaction)
},
});

View File

@@ -1,46 +0,0 @@
import { commandModule, CommandType } from '@sern/handler';
import { AttachmentBuilder } from 'discord.js';
import { publish } from '#plugins';
import { Readable } from 'node:stream'
import { random } from '../../util/randomstring.js';
import fs from 'fs';
import { execa } from 'execa';
export default commandModule({
type: CommandType.CtxMsg,
plugins: [publish()],
execute: async (ctx) => {
await ctx.deferReply({ fetchReply: true })
const text = ctx.targetMessage.content;
const encodedText = encodeURIComponent(text);
const url = `https://www.tetyys.com/SAPI4/SAPI4?text=${encodedText}&voice=Adult%20Male%20%232%2C%20American%20English%20(TruVoice)&pitch=140&speed=157`;
const request = await fetch(url).then(res => res.arrayBuffer())
await new Promise(resolve => setTimeout(resolve, 500));
const randomnumber = random(5)
const randomnumber_wav = `bonzi-wav-${randomnumber}.wav`
const randomnumber_mp3 = `bonzi-mp3-${randomnumber}.mp3`
fs.writeFileSync(`./util/bonzi_temp/${randomnumber_wav}`, new Uint8Array(request))
const command = execa('ffmpeg', [
'-i', `./util/bonzi_temp/${randomnumber_wav}`,
'-vn',
`./util/bonzi_temp/${randomnumber_mp3}`
], { shell: true })
await new Promise((resolve) => {
command.on('close', resolve)
})
const stream = new Readable();
stream._read = () => {};
stream.push(Buffer.from(new Uint8Array(fs.readFileSync(`./util/bonzi_temp/${randomnumber_mp3}`))));
stream.push(null)
const attachment = new AttachmentBuilder(stream, { name: 'bonzied.mp3' })
fs.unlinkSync(`./util/bonzi_temp/${randomnumber_mp3}`)
fs.unlinkSync(`./util/bonzi_temp/${randomnumber_wav}`)
await ctx.editReply({ files: [attachment] })
},
});

View File

@@ -1,21 +0,0 @@
import { commandModule, CommandType } from '@sern/handler';
export default commandModule({
type: CommandType.Button,
execute: async (ctx) => {
await ctx.deferReply({ ephemeral: true })
const getUserID = await ctx.client.users.fetch((ctx.message.embeds[0].footer!.text).replace('Discord ID: ', ''))
await getUserID.send({
content: `Tu solicitud de entrada al servidor ha sido aceptada correctamente!\nYa puedes entrar al servidor con la IP \`minecraft.maraturing.com\``
}).catch(async () => {
await ctx.editReply({
content: `No se ha podido enviar un DM a ${getUserID} <:Sadge:1015764348385382451>`,
})
}).then(async () => {
await ctx.editReply({
content: `Se ha podido enviar un DM a ${getUserID} correctamente! <:Pog:1030169609178976346>`
})
})
},
});

View File

@@ -1,15 +0,0 @@
import { commandModule, CommandType } from '@sern/handler';
import axios from 'axios';
export default commandModule({
type: CommandType.Button,
plugins: [],
execute: async (ctx) => {
await ctx.deferReply({ ephemeral: true })
const request = await axios.get('https://api.minetools.eu/query/minecraft.maraturing.com/25565').then(res => res.data)
await ctx.editReply({
content: ``
})
},
});

View File

@@ -1,35 +0,0 @@
import { commandModule, CommandType } from "@sern/handler";
import type { APISelectMenuComponent, GuildMember } from "discord.js";
export default commandModule({
type: CommandType.StringSelect,
name: 'role-menu',
async execute(interaction) {
await interaction.deferReply({ ephemeral: true });
const roles = interaction.values;
const menuRoles: string[] = (
interaction.message.components[0].components[0]
.data as Readonly<APISelectMenuComponent>
// @ts-ignore
).options.map((o: { label: string; value: string }) => o.value);
const member = interaction.member as GuildMember;
if (!member) return;
let content = `Los roles han sido actualizados. Te he dado estos:\n${roles
.map((r) => `<@&${r}>`)
.join("\n")}`;
if (roles.length === 0) content = "Se han actualizado los roles a ninguno o no se han seleccionado roles...";
const existing = member.roles.cache
.filter((r) => r.id !== interaction.guildId)
.map((r) => r.id)
.filter((r) => !menuRoles.includes(r));
await member.roles.set(roles.concat(existing)).catch(() => null);
await interaction.editReply(content);
},
});

View File

@@ -1,69 +0,0 @@
import { commandModule, CommandType } from '@sern/handler';
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from 'discord.js';
import {
TextChannel,
ThreadAutoArchiveDuration,
} from 'discord.js';
export default commandModule({
type: CommandType.Modal,
async execute(modal) {
const value = modal.fields.getTextInputValue('sugerenciasInput');
function onlySpaces(str: string) {
return str.trim().length === 0;
}
if (onlySpaces(value) === true)
return await modal.reply({
content: 'Buen intento enviando un mensaje vacío >:D',
ephemeral: true,
});
const embed = new EmbedBuilder()
.setColor('Random')
.setTitle('Sugerencia')
.setAuthor({
name: `${modal.user.username}`,
iconURL: `${modal.user.displayAvatarURL()}`,
})
.setDescription(value);
const row = new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setCustomId('suggestions-yes')
.setEmoji('✅')
.setLabel('0')
.setStyle(ButtonStyle.Success),
new ButtonBuilder()
.setCustomId('suggestions-no')
.setEmoji('❎')
.setLabel('0')
.setStyle(ButtonStyle.Danger),
)
const row2 = new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setCustomId('suggestions-yes-who')
.setEmoji('✅')
.setLabel('Quién')
.setStyle(ButtonStyle.Secondary),
new ButtonBuilder()
.setCustomId('suggestions-no-who')
.setEmoji('❎')
.setLabel('Quién')
.setStyle(ButtonStyle.Secondary),
)
const message1 = await (await modal.client.guilds.fetch(process.env.GUILDID!))
.channels.fetch(process.env.SUGGESTIONS_CHANNEL!) as TextChannel;
const message2 = await message1.send({ embeds: [embed], components: [row, row2] });
message2.startThread({
name: `Sugerencia de ${modal.user.username}`,
autoArchiveDuration: ThreadAutoArchiveDuration.ThreeDays,
reason: 'AUTOMATIZADO: Hilo para discutir sobre la sugerencia.',
});
modal.reply({
content:
'¡Enviado!\nRECUERDA QUE NO ESTÁ PERMITIDO ENVIAR MENSAJES VACÍOS.',
ephemeral: true,
});
},
});

View File

@@ -1,24 +0,0 @@
import { commandModule, CommandType } from "@sern/handler";
import db from "../../schemas/suggestions.js";
export default commandModule({
type: CommandType.Button,
async execute(interaction) {
let finalarray
await interaction.deferReply({ephemeral: true})
const findeverything = await db.find({msgid: interaction.message.id, upordown: -1})
const array = findeverything.filter(message => message.msgid)
const fetchedids = await Promise.all(array.map(async (user) => {
return interaction.client.users.fetch(user.userid)
}))
if (fetchedids.length === 0) {
finalarray = 'Nadie, de momento'
} else {
finalarray = fetchedids.join(', ')
}
await interaction.editReply({
content: `Gente que ha hecho downvote:\n${finalarray}`,
allowedMentions: {repliedUser: false}
})
}
})

View File

@@ -1,50 +0,0 @@
import { commandModule, CommandType } from "@sern/handler";
import { ActionRowBuilder, ButtonBuilder, ButtonInteraction, ButtonStyle, ComponentType } from "discord.js";
import db from "../../schemas/suggestions.js";
export default commandModule({
type: CommandType.Button,
async execute(interaction) {
const convertToNumber = Number(interaction.component.label!)
const row2 = new ActionRowBuilder<ButtonBuilder>().setComponents(
new ButtonBuilder(interaction.message!.components[1].components[0].data),
new ButtonBuilder(interaction.message!.components[1].components[1].data)
)
if (await db.exists({msgid: interaction.message.id, userid: interaction.user.id, upordown: 1})) {
await db.findOneAndUpdate({msgid: interaction.message.id, userid: interaction.user.id, upordown: 1}, {upordown: -1}, {returnOriginal: false})
// god forbid I use any! I'm literally done with trying to solve this dude
const upvoteLabel = JSON.stringify(interaction.message!.components[0].components[0].data) as string
const downvotebuttons = new ActionRowBuilder<ButtonBuilder>().setComponents(
new ButtonBuilder(interaction.message!.components[0].components[0].data)
.setLabel((Number(JSON.parse(upvoteLabel).label) - 1).toString()),
new ButtonBuilder()
.setCustomId('suggestions-no')
.setEmoji('❎')
.setLabel((convertToNumber + 1).toString())
.setStyle(ButtonStyle.Danger),
)
await interaction.message.edit({components: [downvotebuttons, row2]})
await interaction.deferUpdate()
} else if (await db.exists({msgid: interaction.message.id, userid: interaction.user.id, upordown: -1})) {
return await interaction.reply({content: 'Ya has hecho downvote.', ephemeral: true})
} else {
const downvotebuttons = new ActionRowBuilder<ButtonBuilder>().setComponents(
new ButtonBuilder(interaction.message!.components[0].components[0].data),
new ButtonBuilder()
.setCustomId('suggestions-no')
.setEmoji('❎')
.setLabel((convertToNumber + 1).toString())
.setStyle(ButtonStyle.Danger),
)
const addToDB = new db({
msgid: interaction.message.id,
userid: interaction.user.id,
upordown: -1
})
await addToDB.save()
await interaction.message.edit({components: [downvotebuttons, row2]})
await interaction.deferUpdate()
}
}
})

View File

@@ -1,25 +0,0 @@
import { commandModule, CommandType } from "@sern/handler";
import { ActionRowBuilder, ButtonBuilder, ButtonInteraction, ButtonStyle, ComponentType } from "discord.js";
import db from "../../schemas/suggestions.js";
export default commandModule({
type: CommandType.Button,
async execute(interaction) {
let finalarray
await interaction.deferReply({ephemeral: true})
const findeverything = await db.find({msgid: interaction.message.id, upordown: 1})
const array = findeverything.filter(message => message.msgid)
const fetchedids = await Promise.all(array.map(async (user) => {
return interaction.client.users.fetch(user.userid)
}))
if (fetchedids.length === 0) {
finalarray = 'Nadie, de momento'
} else {
finalarray = fetchedids.join(', ')
}
await interaction.editReply({
content: `Gente que ha hecho upvote:\n${finalarray}`,
allowedMentions: {repliedUser: false}
})
}
})

View File

@@ -1,50 +0,0 @@
import { commandModule, CommandType } from "@sern/handler";
import { ActionRowBuilder, ButtonBuilder, ButtonInteraction, ButtonStyle, ComponentType } from "discord.js";
import db from "../../schemas/suggestions.js";
export default commandModule({
type: CommandType.Button,
async execute(interaction) {
const convertToNumber = Number(interaction.component.label!)
const row2 = new ActionRowBuilder<ButtonBuilder>().setComponents(
new ButtonBuilder(interaction.message!.components[1].components[0].data),
new ButtonBuilder(interaction.message!.components[1].components[1].data)
)
if (await db.exists({msgid: interaction.message.id, userid: interaction.user.id, upordown: -1})) {
await db.findOneAndUpdate({msgid: interaction.message.id, userid: interaction.user.id, upordown: -1}, {upordown: 1}, {returnOriginal: false})
// god forbid I use any! I'm literally done with trying to solve this dude
const upvoteLabel = JSON.stringify(interaction.message!.components[0].components[1].data) as string
const downvotebuttons = new ActionRowBuilder<ButtonBuilder>().setComponents(
new ButtonBuilder()
.setCustomId('suggestions-yes')
.setEmoji('✅')
.setLabel((convertToNumber + 1).toString())
.setStyle(ButtonStyle.Success),
new ButtonBuilder(interaction.message!.components[0].components[1].data)
.setLabel((Number(JSON.parse(upvoteLabel).label) - 1).toString()),
)
await interaction.message.edit({components: [downvotebuttons, row2]})
await interaction.deferUpdate()
} else if (await db.exists({msgid: interaction.message.id, userid: interaction.user.id, upordown: 1})) {
return await interaction.reply({content: 'Ya has hecho upvote.', ephemeral: true})
} else {
const downvotebuttons = new ActionRowBuilder<ButtonBuilder>().setComponents(
new ButtonBuilder()
.setCustomId('suggestions-yes')
.setEmoji('✅')
.setLabel((convertToNumber + 1).toString())
.setStyle(ButtonStyle.Success),
new ButtonBuilder(interaction.message!.components[0].components[1].data)
)
const addToDB = new db({
msgid: interaction.message.id,
userid: interaction.user.id,
upordown: 1
})
await addToDB.save()
await interaction.message.edit({components: [downvotebuttons, row2]})
await interaction.deferUpdate()
}
}
})

View File

@@ -1,33 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import { ownerOnly } from "#plugins";
import { ApplicationCommandOptionType } from "discord.js";
/*
import { publish } from "#plugins";
import { ownerOnly } from "#plugins"
*/
export default commandModule({
name: 'ip',
type: CommandType.Slash,
plugins: [publish()],
//
description: 'La IP del servidor de Minecraft',
options: [
{
name: 'usuario',
description: 'Menciona al usuario al que va dirigido el comando.',
type: ApplicationCommandOptionType.User
}
],
//alias : [],
execute: async (ctx, options) => {
const usuario = options[1].getMember('usuario');
if (!usuario) {
await ctx.reply({content: "La IP del servidor de Minecraft es `minecraft.maraturing.com`,\nPide acceso con el comando </mcform:1000747672690499594>.", ephemeral: true})
} else {
await ctx.reply({content: `${usuario}` + ", la IP del servidor de Minecraft es `minecraft.maraturing.com`,\nPide acceso con el comando </mcform:1000747672690499594>."})
}
},
});

View File

@@ -1,33 +0,0 @@
import { commandModule, CommandType } from '@sern/handler';
import {
ActionRowBuilder,
ModalBuilder,
TextInputBuilder,
TextInputStyle,
ModalActionRowComponentBuilder,
} from 'discord.js';
import { publish } from '#plugins';
import { ownerOnly } from '#plugins';
export default commandModule({
name: 'mcform',
type: CommandType.Slash,
plugins: [publish()],
description: 'Envia el formulario para entrar al servidor.',
//alias : [],
execute: async (ctx) => {
const modal = new ModalBuilder()
.setCustomId('mcform-main')
.setTitle('Formulario para entrar al servidor');
const input = new TextInputBuilder()
.setCustomId('mcUsernameInput')
.setLabel('Cuál es tu nombre de usuario de Minecraft?')
.setStyle(TextInputStyle.Short);
const usernameActionRow =
new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(
input
);
modal.addComponents(usernameActionRow);
await ctx.interaction.showModal(modal);
},
});

View File

@@ -1,75 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import { ownerOnly } from "#plugins"
import db from '../../schemas/afk.js';
import { ApplicationCommandOptionType, EmbedBuilder } from 'discord.js';
/*
import { publish } from "#plugins";
import { ownerOnly } from "#plugins"
*/
export default commandModule({
type: CommandType.Slash,
plugins: [publish()],
description: 'afk command',
//alias : [],
options: [
{
name: 'añadir',
description: 'Di que estás AFK o inactivo por la razón que quieras.',
type: ApplicationCommandOptionType.Subcommand,
options: [
{
name: 'motivo',
description: 'El motivo por el que estarás AFK',
type: ApplicationCommandOptionType.String,
required: true,
}
]
},
{
name: 'eliminar',
description: 'Elimina tu AFK',
type: ApplicationCommandOptionType.Subcommand
},
{
name: 'lista',
description: 'Listado de todas las personas AFK',
type: ApplicationCommandOptionType.Subcommand
}
],
execute: async (ctx, options) => {
switch (options[1].getSubcommand()) {
case 'añadir': {
if (await db.exists({ id: ctx.user.id })) return ctx.reply({ content: 'Ya existes en la base de datos!', ephemeral: true })
const reason = options[1].getString('motivo', true);
await (new db({ id: ctx.user.id, reason: reason })).save()
const embed = new EmbedBuilder()
.setAuthor({ name: ctx.user.username, iconURL: ctx.user.displayAvatarURL() })
.setTitle('AFK añadido!')
.setColor('Green')
.setDescription(`Razón: ${reason}`)
await ctx.reply({ embeds: [embed] })
} break;
case 'eliminar': {
if (!await db.exists({ id: ctx.user.id })) return ctx.reply({ content: 'No existes en la base de datos!', ephemeral: true })
await db.deleteOne({ id: ctx.user.id })
await ctx.reply('Ok, has sido eliminado correctamente de la base de datos.')
} break;
case 'lista': {
const map = await Promise.all((await db.find()).map(async (doc) => {
return `${await ctx.client.users.fetch(doc.id)}`
}))
await ctx.reply({
content: `Lista de usuarios AFK:\n${(map.length === 0) ? 'Nadie' : map.join(', ')}`,
allowedMentions: { repliedUser: false }
})
} break;
}
},
});

View File

@@ -1,19 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import { ownerOnly } from "#plugins";
import { ApplicationCommandOptionType } from "discord.js";
/*
import { publish } from "#plugins";
import { ownerOnly } from "#plugins"
*/
export default commandModule({
name: 'askjavi',
type: CommandType.Slash,
plugins: [publish()],
description: 'DESACTIVADO: Pregunta a Javi LO QUE SEA!',
//alias : [],
execute: async (ctx, options) => {
await ctx.reply({content: `Este comando ha sido desactivado ya que era para un evento que ya ha ocurrido.\nGracias por haber participado!`, ephemeral: true})
},
});

View File

@@ -1,192 +0,0 @@
import { commandModule, CommandType } from '@sern/handler';
import {
ActionRowBuilder,
ModalBuilder,
TextInputBuilder,
TextInputStyle,
ModalActionRowComponentBuilder,
ButtonBuilder,
ButtonStyle,
ComponentType,
ModalSubmitInteraction,
ApplicationCommandOptionType,
} from 'discord.js';
import { publish } from '#plugins';
import { ownerOnly } from '#plugins';
import padyama from '../../schemas/padyama.js';
import { random } from '../../util/randomstring.js';
export default commandModule({
name: 'askjavi',
type: CommandType.Slash,
plugins: [
// publish(),
],
description: 'TEMP: Pregunta a Javi LO QUE SEA!',
//alias : [],
options: [
{
name: 'new',
description: 'Haz una nueva pregunta',
type: ApplicationCommandOptionType.Subcommand,
},
{
name: 'get',
description: 'Mira una pregunta teniendo su ID.',
type: ApplicationCommandOptionType.Subcommand,
options: [
{
name: 'id',
description: 'El ID de la pregunta',
type: ApplicationCommandOptionType.String,
required: true,
},
],
},
{
name: 'you',
description: 'Todos los IDs de las preguntas que hayas hecho',
type: ApplicationCommandOptionType.Subcommand,
},
{
name: 'answered',
description:
'ORGANIZADOR: Todos los IDs de las preguntas que hayas hecho',
type: ApplicationCommandOptionType.Subcommand,
options: [
{
name: 'id',
description: 'El ID de la pregunta',
type: ApplicationCommandOptionType.String,
required: true,
},
],
},
],
execute: async (ctx, options) => {
switch (ctx.interaction.options.getSubcommand()) {
case 'new': {
const modal = new ModalBuilder()
.setCustomId('askjavi')
.setTitle('Sugerencias');
const input = new TextInputBuilder()
.setCustomId('askjavi-prompt')
.setLabel('Qué quieres preguntarle?')
.setStyle(TextInputStyle.Paragraph);
const suggestionsActionRow =
new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(
input
);
modal.addComponents(suggestionsActionRow);
const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder()
.setCustomId('askjavi-buttons-yes')
.setLabel('Sí!')
.setStyle(ButtonStyle.Success),
new ButtonBuilder()
.setCustomId('askjavi-buttons-no')
.setLabel('Ok mejor no')
.setStyle(ButtonStyle.Danger)
);
const message = await ctx.reply({
content: `No puedes enviar sugerencias inútiles o spam.\nSi haces esto, serás descalificado.\nContinuas?`,
components: [buttons],
ephemeral: true,
});
const collector = message.createMessageComponentCollector({
max: 1,
componentType: ComponentType.Button,
time: 60_000,
});
collector.on('collect', async (i) => {
if (i.customId === 'askjavi-buttons-yes') {
const suggestionid = random(5);
await i.showModal(modal);
await ctx.interaction.editReply({
components: [],
});
const submitted = (await ctx.interaction
.awaitModalSubmit({
time: 180000,
filter: (i) => i.user.id === ctx.user.id,
})
.catch((error) => {})) as ModalSubmitInteraction;
const db = new padyama({
id: i.user.id,
user: i.user.username,
suggestionid: suggestionid,
suggestion: submitted.fields.getTextInputValue('askjavi-prompt'),
});
await db.save();
await submitted.reply({
content: `Tu pregunta ha sido registrada en la base de datos correctamente.\nEl ID de esta pregunta es: \`${suggestionid}\`. Se te contactará por DMs cuando se responda la pregunta.\nPuedes ver tus IDs de preguntas con el comando </askjavi you:1040938647001776199>.`,
ephemeral: true,
});
}
if (i.customId === 'askjavi-buttons-no') {
await ctx.interaction.editReply({
content: 'Ok pues...',
components: [],
});
}
});
}
case 'get': {
const option = options[1].getString('id');
const db = await padyama.findOne({ suggestionid: option });
if (db?.suggestion !== undefined)
return await ctx.reply({
content: `La sugerencia es:\n${db?.suggestion}`,
ephemeral: true,
});
else
return await ctx.reply({
content: `Parece que ese ID no se ha encontrado...`,
ephemeral: true,
});
}
case 'you': {
const db = await padyama.find({ id: ctx.user.id });
await ctx.reply({
content: `Los IDs de las preguntas que has hecho:\n${db.map(
(doc) => `\`${doc.suggestionid}\``
)}`,
ephemeral: true,
});
}
case 'answered': {
if (ctx.user.id !== '703974042700611634')
return await ctx.reply({
content: `No puedes usar este comando.`,
ephemeral: true,
});
const option = options[1].getString('id');
const db = await padyama.findOne({ suggestionid: option });
if (db?.user !== undefined) {
try {
await (await ctx.user.fetch(db?.id))
.send({
content: `Hola!\nRespecto al AMA del sevidor de Mara:\nTu pregunta con ID \`${option}\` ha sido respondida correctamente!`,
})
.then(async () => {
await ctx.reply({
content: `DM enviado correctamente!`,
ephemeral: true,
});
});
} catch {
await ctx.reply({
content: `Parece que no se ha podido enviar el DM...`,
ephemeral: true,
});
}
} else {
await ctx.reply({
content: `No se ha encontrado el usuario enlazado con el ID en cuestión...`,
ephemeral: true,
});
}
}
}
},
});

View File

@@ -1,50 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { Context, SlashOptions } from "@sern/handler";
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js";
import { publish } from "#plugins";
export default commandModule({
name: 'creditos',
type: CommandType.Slash,
plugins: [publish()],
description: 'Créditos del bot (en inglés)',
//alias : [],
options: [],
execute: async (ctx, options) => {
const baseEmbed = new EmbedBuilder()
.setColor('Blurple')
.setTitle(`Without these people, the bot wouldn't exist!`)
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
.setFooter({text: `Created by Sr Izan | This list will be expanded`, iconURL: ctx.client.user?.displayAvatarURL()})
const page1 = baseEmbed
.setDescription(`**Development**\n
<@703974042700611634>: Main development.\n
<@464397024247152640>: Trusting me and inviting the bot.\n
**For helping me out**\n
<@182326315813306368>: sern handler dev, helper at WOK, such a cool guy and helper <3\n
<@697795666373640213>: sern handler dev, also helper at WOK, helped me out a ton\n
*Some people at the D.JS discord*: yeah\n
**Motivation**\n
<@719678368173523015>: WHAT ARE YOU DOING ON VINCI RN?!?!?!\n
<@530870655005097995>: Gave some ideas on the *original* roadmap\n
<@678000774441336842>: My good'ol friend, always has been trying new Vinci stuff\n
<@758743564879659069>: Believe it or not, this looper has alvays been beta-testing stuff\n
<@697146020647403651>: For always thanking all my work\n
<@630502288154427414>: he bans everyone on my twitch\n
**And, of course, you <3**\n
Thanks everyone, this has been an absolute ride, I don't have words to express my appreciation! <:Pepelove:1030904410307563542>
`)
const buttons = new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setLabel('lol')
.setURL('https://discord.com/channels/928018226330337280/928018227156643857/1030480463690731530')
.setStyle(ButtonStyle.Link),
new ButtonBuilder()
.setLabel('<3')
.setURL('https://discord.com/channels/928018226330337280/1030913456846680134')
.setStyle(ButtonStyle.Link)
)
await ctx.reply({embeds: [page1], components: [buttons], ephemeral: true})
},
});

View File

@@ -1,61 +0,0 @@
import { commandModule, CommandType } from "@sern/handler";
import { publish } from "#plugins";
import { ApplicationCommandOptionType } from "discord.js";
import { readFileSync } from "node:fs";
import birthdays from "../../schemas/birthdays.js";
import { acceptingBirthday } from "#plugins";
/*
import { publish } from "#plugins";
import { ownerOnly } from "#plugins"
*/
export default commandModule({
name: "cumple",
type: CommandType.Slash,
plugins: [publish(), acceptingBirthday()],
description: "Pon tu cumpleaños en la base de datos para ser felicitado!",
//alias : [],
options: [
{
name: "fecha",
description: "La fecha de tu cumple (D-M) (elige en el autocompletado)",
type: ApplicationCommandOptionType.String,
autocomplete: true,
required: true,
command: {
onEvent: [],
execute: async (autocomplete) => {
const focusedValue = autocomplete.options.getFocused();
let choices = JSON.parse(
String(readFileSync("./util/daysinyear.txt"))
) as Array<string>;
choices = choices.filter((choice) =>
choice.toString().startsWith(focusedValue)
);
choices = choices.slice(0, 25);
await autocomplete.respond(
choices.map((choice) => ({
name: choice.toString(),
value: choice,
}))
);
},
},
},
],
execute: async (ctx, options) => {
const option = ctx.interaction.options.getString("fecha")
const array = JSON.parse(
String(readFileSync("./util/daysinyear.txt"))
) as Array<string>;
if (!array.includes(option!)) return await ctx.interaction.editReply('Asegúrate que estás eligiendo una fecha del autocompletado!')
if (await birthdays.exists({id: ctx.user.id})) return await ctx.interaction.editReply('No puedes poner tu fecha de nuevo!')
const db = new birthdays({
id: ctx.user.id,
date: option,
alreadysent: false
});
await db.save();
await ctx.interaction.editReply('Ok, guardado correctamente. No puedes volver a cambiar la fecha.')
},
});

View File

@@ -1,66 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { ApplicationCommandOptionType, ColorResolvable, EmbedBuilder } from 'discord.js';
import { publish } from "#plugins";
import fs from 'node:fs';
import mctags from '../../util/tags/minecraft.json' assert { type: 'json' }
export default commandModule({
type: CommandType.Slash,
plugins: [publish()],
description: 'Preguntas normalmente preguntadas :pepega:',
//alias : [],
options: [
{
name: 'minecraft',
description: 'Preguntas normalmente preguntadas de Minecraft',
type: ApplicationCommandOptionType.Subcommand,
options: [
{
name: 'pregunta',
description: 'La pregunta',
type: ApplicationCommandOptionType.String,
autocomplete: true,
required: true,
command: {
onEvent: [],
execute: async (ctx) => {
const query = ctx.options.getFocused()
const filter = mctags.filter(obj => obj.title.includes(query))
await ctx.respond(
filter.map(map => ({ name: map.title.toString(), value: map.title.toString() }))
)
}
}
},
{
name: 'para',
description: 'Menciona a la persona a la que vaya esto.',
type: ApplicationCommandOptionType.User,
}
]
}
],
execute: async (ctx, options) => {
switch (options[1].getSubcommand()) {
case 'minecraft': {
const option = options[1].getString('pregunta', true)
const forusr = options[1].getMember('para')
const filter = mctags.filter(obj => obj.title.includes(option))[0]
const embed = new EmbedBuilder()
.setAuthor({ name: ctx.user.username, iconURL: ctx.user.displayAvatarURL() })
.setColor(filter.color as ColorResolvable)
.setTitle(filter.title)
.setDescription(filter.text)
if (forusr) {
await ctx.reply({
content: `Esto es para tí ${forusr}:`,
embeds: [embed]
})
} else {
await ctx.reply({ embeds: [embed] })
}
} break;
}
},
});

View File

@@ -1,34 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import google from 'googlethis'
import { ApplicationCommandOptionType } from 'discord.js';
/*
import { publish } from "#plugins";
import { ownerOnly } from "#plugins"
*/
export default commandModule({
type: CommandType.Slash,
plugins: [publish()],
description: 'Busca cosas en Google.',
//alias : [],
options: [
{
name: 'busqueda',
description: 'Escribe qué quieres buscar',
type: ApplicationCommandOptionType.String,
required: true,
}
],
execute: async (ctx, options) => {
await ctx.interaction.deferReply()
const prompt = options[1].getString('busqueda', true)
const search = await Promise.all((await google.search(prompt)).results.map(res => {
return `[${res.title}](<${res.url}>)`
}).slice(0, 5))
await ctx.interaction.editReply({
content: `Resultados para la búsqueda \`${prompt}\`:\n${search.join('\n')}`
})
},
});

View File

@@ -1,60 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import Genius from 'genius-lyrics'
import { ActionRowBuilder, ApplicationCommandOptionType, ButtonBuilder, ButtonStyle, EmbedBuilder } from 'discord.js';
const genius = new Genius.Client(process.env.GENIUS)
export default commandModule({
type: CommandType.Slash,
plugins: [publish()],
description: 'Busca la letra de una canción (Genius)',
//alias : [],
options: [
{
name: 'busqueda',
description: 'Qué buscar',
type: ApplicationCommandOptionType.String,
required: true,
autocomplete: true,
command: {
onEvent: [],
execute: async (ctx) => {
const input = ctx.options.getFocused();
const choices = (await genius.songs.search(input)).map(res => {
return `${res.title} - ${res.artist.name}|${res.id}`
})
await ctx.respond(
choices.map(choice => {
const [title, id] = choice.split('|')
return ({name: title, value: id})
})
)
}
}
}
],
execute: async (ctx, options) => {
await ctx.interaction.deferReply({ ephemeral: true })
const prompt = options[1].getString('busqueda', true)
const result = await genius.songs.get(Number(prompt))
const embed = new EmbedBuilder()
.setTitle(`${result.title} - ${result.artist.name}`)
.setColor('Random')
.setDescription((await result.lyrics()).slice(0, 3000))
const button = new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setLabel('URL de Genius')
.setStyle(ButtonStyle.Link)
.setURL(result.url)
)
await ctx.interaction.editReply({
embeds: [embed],
components: [button]
})
},
});

View File

@@ -1,98 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import { createAudioPlayer, createAudioResource, DiscordGatewayAdapterCreator, joinVoiceChannel } from "@discordjs/voice";
import got from "got";
import { ApplicationCommandOptionType, EmbedBuilder } from "discord.js";
/*
import { publish } from "#plugins";
import { ownerOnly } from "#plugins"
*/
export default commandModule({
name: 'radio',
type: CommandType.Slash,
plugins: [publish()],
description: 'Reproduce la radio',
options: [
{
name: 'reproducir',
description: 'Reproduce una radio de la lista',
type: ApplicationCommandOptionType.String,
autocomplete: true,
required: true,
command: {
onEvent: [],
async execute(ctx){
const focusedValue = ctx.options.getFocused();
const choices = ['Rock FM', 'Cadena 100', 'Cadena Dial', 'Gensokyo Radio', 'BBC 1', 'RNE 1', 'RNE 5', 'Los 40', 'Flaixbac', 'FlaixFM'];
const filtered = choices.filter(choice => choice.startsWith(focusedValue));
await ctx.respond(
filtered.map(choice => ({ name: choice, value: choice })),
);
}
}
}
],
execute: async (ctx, options) => {
const radioname = options[1].getString("reproducir", true)
const embed = new EmbedBuilder()
.setColor("Green")
.setTitle(`Reproduciendo ${radioname} en Vinci Radio.`)
.setDescription(`A veces la radio tarda en cargar, sé paciente :'D`);
const notFoundEmbed = new EmbedBuilder()
.setColor("Red")
.setTitle(`Radio ${radioname} no encontrada.`)
.setDescription(`La radio no ha sido encontrada, asegúrate que la radio está escogida de la lista.`);
async function playRadio(radioname: string, isFlaix?: boolean) {
const stream = got.stream(radioname)
const connection = joinVoiceChannel({adapterCreator: ctx.interaction.guild!.voiceAdapterCreator as DiscordGatewayAdapterCreator, channelId: '1008730592835281009',guildId: '928018226330337280',selfDeaf: true});
const resource = createAudioResource(stream, { inlineVolume: true });
const player = createAudioPlayer();
connection.subscribe(player)
player.play(resource)
if (isFlaix === true) {
resource.volume!.setVolume(0.3)
} else {
resource.volume!.setVolume(0.7)
}
await ctx.reply({embeds: [embed], ephemeral: true})
}
switch (radioname) {
case 'Rock FM': {
playRadio("https://flucast-m04-06.flumotion.com/cope/rockfm.mp3")
} break;
case 'Cadena 100': {
playRadio("https://server8.emitironline.com:18196/stream")
} break;
case 'Cadena Dial': {
playRadio("http://20853.live.streamtheworld.com/CADENADIAL.mp3")
} break;
case 'BBC 1': {
playRadio("http://stream.live.vc.bbcmedia.co.uk/bbc_radio_one")
} break;
case 'RNE 1': {
playRadio("https://crtve--di--crtve-ice--01--cdn.cast.addradio.de/crtve/rne1/main/mp3/high")
} break;
case 'RNE 5': {
playRadio("https://crtve--di--crtve-ice--01--cdn.cast.addradio.de/crtve/rne5/main/mp3/high")
} break;
case 'Los 40': {
playRadio('http://stream.ondaceronoroeste.es:8000/stream')
} break;
case 'Gensokyo Radio': {
playRadio('https://stream.gensokyoradio.net/3')
} break;
case 'Flaixbac': {
playRadio('https://nodo07-cloud01.streaming-pro.com:8005/flaixbac.mp3', true)
} break;
case 'FlaixFM': {
playRadio('https://nodo07-cloud01.streaming-pro.com:8001/flaixfm.mp3', true)
} break;
default: {
await ctx.reply({embeds: [notFoundEmbed], ephemeral: true})
} break;
}
},
});

View File

@@ -1,37 +0,0 @@
import { commandModule, CommandType } from "@sern/handler";
import axios, { AxiosError, AxiosResponse } from "axios";
import { ApplicationCommandOptionType } from "discord.js";
import { publish } from "#plugins";
export default commandModule({
name: "acortar",
type: CommandType.Slash,
plugins: [
publish(),
],
description: "Acorta una URL a vinci.tk",
options: [
{
name: "url",
description: "la URL larga",
type: ApplicationCommandOptionType.String,
required: true,
},
],
//alias : [],
execute: async (ctx, options) => {
const url = options[1].getString("url", true);
const request = await axios(
`https://vinci.tk/yourls-api.php?signature=${process.env.YOURLS_KEY}&action=shorturl&format=json&url=${url}`,
{
validateStatus: function (status) {
return status === 200 || status === 400;
},
}
).then((res: AxiosResponse) => res.data);
ctx.reply({
content: `URL acortada: <${request.shorturl}>\nURL original: <${url}>`,
ephemeral: true,
});
},
});

View File

@@ -1,44 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import { ownerOnly } from "#plugins";
import { EmbedBuilder } from "discord.js";
import axios from "axios";
import prettySeconds from 'pretty-seconds-spanish'
export default commandModule({
name: 'stats',
type: CommandType.Slash,
plugins: [publish()],
description: 'Enseña estadísticas del bot.',
//alias : [],
options: [],
execute: async (ctx, options) => {
await ctx.interaction.deferReply({ ephemeral: true })
const cpubrand = await axios(`http://192.168.1.79:7271/cpubrand`)
const cpucores = await axios(`http://192.168.1.79:7271/cpucores`)
const ramtotal = await axios(`http://192.168.1.79:7271/ramtotal`)
const ramfree = await axios(`http://192.168.1.79:7271/ramfree`)
const dockertotal = await axios(`http://192.168.1.79:7271/dockertotal`)
const uptime = prettySeconds(process.uptime())
const embed = new EmbedBuilder()
.setAuthor({name: `${ctx.user.username}`, iconURL: `${ctx.user.displayAvatarURL()}`})
.setTitle(`Estadísticas de Vinci.`)
.setThumbnail(`https://i.imgur.com/UwC1x8T.png`)
.setURL('https://status.vinci.tk')
.setColor('Random')
.addFields(
{name: "Fabricante de CPU", value: `${cpubrand.data}`, inline: true},
{name: `Núcleos de CPU`, value: `${cpucores.data}`, inline: true},
{name: '\u200B', value: '\u200B', inline: true},
{name: `RAM total`, value: `${ramtotal.data}`, inline: true},
{name: `RAM libre`, value: `${ramfree.data}`, inline: true},
{name: '\u200B', value: '\u200B', inline: true},
{name: 'Contenedores de Docker', value: `${dockertotal.data}`, inline: true},
{name: '\u200B', value: '\u200B', inline: true},
{name: 'Tiempo encendido', value: `${uptime}`},
// {name: '\u200B', value: '\u200B', inline: true},
// {name: 'Uptime del servidor', value: `${prettySeconds(`${nodeuptime.data}`)}`}
)
await ctx.interaction.editReply({embeds: [embed]})
},
});

View File

@@ -1,32 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { ActionRowBuilder, ModalBuilder, TextInputBuilder, TextInputStyle, ModalActionRowComponentBuilder } from 'discord.js'
import { publish } from "#plugins";
import { ownerOnly } from "#plugins";
export default commandModule({
name: 'sugerencias',
type: CommandType.Slash,
plugins: [publish()],
description: 'Envia una sugerencia.',
//alias : [],
execute: async (ctx) => {
const modal = new ModalBuilder()
.setCustomId('sugerencias')
.setTitle('Sugerencias');
// Create the text input components
const input = new TextInputBuilder()
.setCustomId('sugerenciasInput')
// The label is the prompt the user sees for this input
.setLabel("Tienes sugerencias?")
// Short means only a single line of text
.setStyle(TextInputStyle.Paragraph);
// An action row only holds one text input,
// so you need one action row per text input.
const suggestionsActionRow = new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(input);
// Add inputs to the modal
modal.addComponents(suggestionsActionRow);
await ctx.interaction.showModal(modal);
}
});

View File

@@ -1,97 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import { ownerOnly } from "#plugins";
import axios from 'axios';
import { readFileSync } from 'node:fs'
import { ActionRowBuilder, ApplicationCommandOptionType, ButtonBuilder, ButtonStyle, ComponentType, EmbedBuilder } from 'discord.js';
const choices = ['es', 'en', 'fr', 'de', 'hi', 'it', 'ja', 'ko', 'pl']
/*
import { publish } from "#plugins";
import { ownerOnly } from "#plugins"
*/
export default commandModule({
type: CommandType.Slash,
plugins: [publish()],
// , '928018226330337280'
description: 'Traduce lo que quieras!',
//alias : [],
options: [
{
name: 'frase',
description: 'La frase que traducir',
type: ApplicationCommandOptionType.String,
required: true
},
{
name: 'idioma',
description: 'El idioma al que quieras traducir',
type: ApplicationCommandOptionType.String,
required: true,
autocomplete: true,
command: {
onEvent: [],
execute: async (interaction) => {
const focusedValue = interaction.options.getFocused();
const filtered = choices.filter(choice => choice.startsWith(focusedValue))
await interaction.respond(
filtered.map((choice) => ({
name: choice,
value: choice,
}))
);
}
}
}
],
execute: async (ctx, options) => {
const langToTranslate = options[1].getString('idioma', true)
const stringToTranslate = options[1].getString('frase', true)
if (choices.indexOf(langToTranslate) === -1)
return ctx.reply({content: 'Elige un idioma del autocompletado.'})
await ctx.interaction.deferReply()
const before = performance.now()
const request = await axios.post('https://translate.nvda.es/translate',
{
q: stringToTranslate,
source: "auto",
target: langToTranslate,
format: "text",
api_key: ""
},
{
headers: {
'Content-Type': 'application/json'
}
}
).then(res => res.data)
const button = new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setCustomId('translate-original')
.setLabel('Texto original')
.setStyle(ButtonStyle.Primary)
)
const after = performance.now()
const embed = new EmbedBuilder()
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
.setTitle(`La traducción pedida. He tardado \`${(after - before).toFixed(2)}ms\`.`)
.setDescription(request.translatedText as string)
.setFooter({text: 'Traducido por LibreTranslate'})
const message = await ctx.interaction.editReply({embeds: [embed], components: [button]})
const collector = message.createMessageComponentCollector({componentType: ComponentType.Button, time: 60_000})
collector.on('collect', async (i) => {
if (i.customId !== 'translate-original') return
await i.reply({content: `La traducción original es:\n\`\`\`${stringToTranslate}\`\`\``, ephemeral: true})
})
},
});

View File

@@ -1,17 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import prettySeconds from 'pretty-seconds-spanish'
export default commandModule({
name: 'uptime',
type: CommandType.Slash,
plugins: [publish()],
description: 'Enseña el tiempo que ha estado encendido el bot.',
//alias : [],
options: [],
execute: async (ctx, options) => {
// const uptime = prettyMilliseconds(ctx.client.uptime!)
const uptime = prettySeconds(process.uptime())
await ctx.reply(`El bot lleva encendido ${uptime}`);
},
});

View File

@@ -1,36 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import { ownerOnly } from "#plugins";;
import { ApplicationCommandOptionType, EmbedBuilder, GuildMember, TextChannel } from 'discord.js'
export default commandModule({
name: 'ban',
type: CommandType.Slash,
plugins: [publish(), ownerOnly()],
description: 'ADMIN: Banea usuarios.',
options: [{
name: 'usuario',
description: 'Escribe un usuario.',
type: ApplicationCommandOptionType.User,
required: true
},
{
name: 'razon',
description: 'Escribe la razón.',
type: ApplicationCommandOptionType.String,
required: true
}],
//alias : [],
execute: async (ctx, options) => {
try {
const userToBan = options[1].getMember('usuario') as GuildMember
const reason = options[1].getString('razon') as string
userToBan.ban({reason: reason})
const sendToMods = ctx.client.guilds.cache.get(process.env.GUILDID!)!.channels.cache.get(process.env.MODLOGS_CHANNEL!) as TextChannel
await sendToMods.send({content: `Se ha baneado a ${userToBan}.\nBan efectuado por ${ctx.user} con razón "${reason}."`})
await ctx.reply({content: 'Baneado correctamente!', ephemeral: true})
} catch {
await ctx.reply({content: `ERROR: No puedo hacer este comando porque a lo mejor soy inferior que el rol de esa persona o estoy usándolo contra admins.`})
}
},
});

View File

@@ -1,42 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "../../plugins/index.js";
import { ownerOnly } from "#plugins";
import { ApplicationCommandOptionType, TextChannel } from "discord.js";
/*
import { publish } from "#plugins";
import { ownerOnly } from "#plugins"
*/
export default commandModule({
name: 'eliminarmensaje',
type: CommandType.Slash,
plugins: [publish(), ownerOnly()],
description: 'ADMIN: Elimina comandos por su ID.',
//alias : [],
options: [
{
name: 'canal',
type: ApplicationCommandOptionType.Channel,
description: 'El canal de texto.',
required: true
},
{
name: 'id',
type: ApplicationCommandOptionType.String,
description: 'El ID del mensaje.',
required: true
}
],
execute: async (ctx, options) => {
try {
const idMensaje = options[1].getString('id', true);
const guildId = ctx.guild!.id
const guild = await ctx.client.guilds.fetch(guildId);
const channel = await guild.channels.fetch(ctx.channel!.id);
(await (channel as TextChannel).messages.fetch(idMensaje)).delete();
await ctx.reply({content: 'Mensaje eliminado correctamente.', ephemeral: true});
} catch {
await ctx.reply({content: `ERROR: No se ha podido eliminar el mensaje, asegúrate que estás usando el ID y el canal correcto.`})
}
},
});

View File

@@ -1,38 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import { ownerOnly } from "#plugins";;
import { ApplicationCommandOptionType, EmbedBuilder, GuildMember, TextChannel } from 'discord.js'
export default commandModule({
name: 'kick',
type: CommandType.Slash,
plugins: [publish(), ownerOnly()],
description: 'ADMIN: Expulsa usuarios.',
options: [
{
name: 'usuario',
description: 'Escribe un usuario.',
type: ApplicationCommandOptionType.User,
required: true
},
{
name: 'razon',
description: 'Escribe la razón.',
type: ApplicationCommandOptionType.String,
required: true
}
],
//alias : [],
execute: async (ctx, options) => {
try {
const userToKick = options[1].getMember('usuario');
const reason = options[1].getString('razon') as string;
(userToKick as GuildMember).kick(reason)
const sendToMods = ctx.client.guilds.cache.get(process.env.GUILDID!)!.channels.cache.get(process.env.MODLOGS_CHANNEL!) as TextChannel
await sendToMods!.send({content: `Se ha expulsado a ${userToKick}.\nKick efectuado por ${ctx.user} con razón "${reason}."`})
await ctx.reply({content: 'Expulsado correctamente!'})
} catch {
await ctx.reply({content: `ERROR: No puedo hacer este comando porque a lo mejor soy inferior que el rol de esa persona o estoy usándolo contra admins.`})
}
},
});

View File

@@ -1,32 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import { ownerOnly } from "#plugins";;
import { ApplicationCommandOptionType, TextChannel } from 'discord.js'
export default commandModule({
name: 'prune',
type: CommandType.Slash,
plugins: [publish(), ownerOnly()],
description: 'ADMIN: Elimina hasta 100 mensajes',
options: [{
name: 'numero',
description: 'Escribe un número',
type: ApplicationCommandOptionType.Number,
required: true,
min_value: 1,
max_value: 100
}],
//alias : [],
execute: async (ctx, options) => {
try {
const amount = options[1].getNumber('numero', true) as number
(ctx.channel as TextChannel).bulkDelete(amount).catch(err => {
console.error(err);
ctx.reply({content: 'Ha habido un error eliminando mensajes! (mira la consola, Sr Izan)', ephemeral: true});});
await ctx.reply({content: `Se han eliminado ${amount} mensajes.`})
const sendToMods = ctx.client.guilds.cache.get(process.env.GUILDID!)!.channels.cache.get(process.env.MODLOGS_CHANNEL!) as TextChannel
await sendToMods.send({content: `Se han eliminado ${amount} mensajes en ${ctx.channel}\nEfectuado por ${ctx.user}.`})
} catch {
ctx.reply({content: 'Ha habido un error eliminando mensajes! Error reportado automáticamente.', ephemeral: true})};
}
});

View File

@@ -1,40 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import { ownerOnly } from "#plugins";
import { ApplicationCommandOptionType, TextChannel } from "discord.js";
export default commandModule({
name: 'slowmode',
type: CommandType.Slash,
plugins: [publish(), ownerOnly()],
description: 'ADMIN: Pon modo lento a canales de texto',
options: [
{
name: "segundos",
description: "Los segundos de modo lento",
type: ApplicationCommandOptionType.Number,
required: true
},
{
name: "razon",
description: "La razón del modo lento",
type: ApplicationCommandOptionType.String,
required: true
}
],
//alias : [],
execute: async (ctx, options) => {
try {
const seconds = options[1].getNumber("segundos", true);
const reason = options[1].getString("razon", true);
(ctx.channel as TextChannel).setRateLimitPerUser(seconds, reason)
ctx.reply({content: `Se han añadido ${seconds} segundos de modo lento al canal de voz actual`})
const sendToMods = ctx.client.guilds.cache.get(process.env.GUILDID!)!.channels.cache.get(process.env.MODLOGS_CHANNEL!) as TextChannel
await sendToMods.send({content: `Se ha aplicado modo lento al canal ${ctx.channel}.\nEfectuado por ${ctx.user} con ${seconds} segundos de retardo.\nRazón: ${reason}`})
} catch {
ctx.reply({content: `No se ha podido aplicar modo lento al canal.`})
}
},
});

View File

@@ -1,50 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import { ownerOnly } from "#plugins";
import { ApplicationCommandOptionType, GuildMember, TextChannel } from "discord.js";
/*
import { publish } from "#plugins";
import { ownerOnly } from "#plugins"
*/
export default commandModule({
name: 'timeout',
type: CommandType.Slash,
plugins: [publish(), ownerOnly()],
description: 'ADMIN: Silencia a usuarios.',
options: [
{
name: "usuario",
description: "Escribe el usuario que silenciar.",
type: ApplicationCommandOptionType.User,
required: true
},
{
name: "razon",
description: "Escribe el razon que vas a silenciar.",
type: ApplicationCommandOptionType.String,
required: true
},
{
name: "minutos",
description: "Escribe los minutos que estará silenciado.",
type: ApplicationCommandOptionType.Number,
min_value: 0,
required: true
}
],
//alias : [],
execute: async (ctx, options) => {
try {
const usuario = options[1].getMember('usuario') as GuildMember
const minutos = options[1].getNumber('minutos') as number
const razon = options[1].getString('razon', true);
const minutosToMilisegundos = minutos * 60 * 1000
usuario.timeout(minutosToMilisegundos, razon).then(() => {ctx.reply({content: `Se ha silenciado a ${usuario} correctamente.`, ephemeral: true})})
const sendToMods = ctx.client.guilds.cache.get(process.env.GUILDID!)!.channels.cache.get(process.env.MODLOGS_CHANNEL!) as TextChannel
await sendToMods.send({content: `Se ha silenciado a ${usuario}.\nSlencio efectuado por ${ctx.user} con ${minutos} minutos de duración.\nRazón: ${razon}`})
} catch {
await ctx.reply({content: `ERROR: No puedo hacer este comando porque a lo mejor soy inferior que el rol de esa persona o estoy usándolo contra admins.`})
}
},
});

View File

@@ -1,212 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import { ownerOnly } from "#plugins";;
import { ActionRowBuilder, ApplicationCommandOptionType, ButtonBuilder, ButtonInteraction, ButtonStyle, ComponentType, EmbedBuilder, GuildMember } from "discord.js";
import db from '../../schemas/warn.js';
export default commandModule({
name: 'warn',
type: CommandType.Slash,
plugins: [publish(), ownerOnly()],
description: 'ADMIN: Avisa a usuarios.',
//alias : [],
options: [
{
name: 'leve',
description: 'Aviso leve.',
type: ApplicationCommandOptionType.Subcommand,
options: [
{
name: 'usuario',
description: 'el usuario al que avisar.',
type: ApplicationCommandOptionType.User,
required: true
},
{
name: 'razon',
description: 'la razón aviso.',
type: ApplicationCommandOptionType.String,
required: true
}
]
},
{
name: 'grave',
description: 'Aviso grave.',
type: ApplicationCommandOptionType.Subcommand,
options: [
{
name: 'usuario',
description: 'el usuario al que avisar.',
type: ApplicationCommandOptionType.User,
required: true
},
{
name: 'razon',
description: 'la razón del aviso.',
type: ApplicationCommandOptionType.String,
required: true
}
]
},
{
name: 'clear',
description: 'Elimina los avisos de una persona.',
type: ApplicationCommandOptionType.Subcommand,
options: [
{
name: 'usuario',
description: 'el usuario al que quitar el aviso.',
type: ApplicationCommandOptionType.User,
required: true
}
]
}
],
execute: async (ctx, options) => {
const subcommand = options[1].getSubcommand()
const user = (options[1].getMember('usuario') as GuildMember).id
const usermember = options[1].getMember('usuario') as GuildMember
const reason = options[1].getString('razon', true) as string
const times = await db.findOne({id: `${user}`}) as any
const buttons = new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setCustomId('1hour')
.setLabel('1 hora')
.setStyle(ButtonStyle.Danger),
new ButtonBuilder()
.setCustomId('30mins')
.setLabel('30 minutos')
.setStyle(ButtonStyle.Danger),
new ButtonBuilder()
.setCustomId('15mins')
.setLabel('15 minutos')
.setStyle(ButtonStyle.Danger),
new ButtonBuilder()
.setCustomId('pardon')
.setLabel('Perdonar')
.setStyle(ButtonStyle.Primary)
);
const dmEmbed = new EmbedBuilder()
.setAuthor({name: `${ctx.user.username}`, iconURL: `${ctx.user.displayAvatarURL()}`})
.setColor('Red')
.setTitle('Tienes un aviso.')
.setDescription(`Has sido avisado en el servidor de Discord.\nRazón: ${reason}.`)
const dmEmbedTimeout = new EmbedBuilder()
.setAuthor({name: `${ctx.user.username}`, iconURL: `${ctx.user.displayAvatarURL()}`})
.setColor('Red')
.setTitle('Acabas de ser muteado del servidor.')
.setDescription(`Ve al servidor de Discord para ver el tiempo que estarás bloqueado.\nRazón: ${reason}.\n**Puede durar hasta una hora.**`)
switch (subcommand) {
case "leve": {
return db.exists({id: `${user}`}, async function (err, doc) {
if (err) {
console.log(err)
} else {
if (doc === null) {
const warn = new db({id: `${user}`, times: 1})
warn.save()
ctx.reply({content: `Se ha avisado a ${usermember} correctamente y añadido a la base de datos.`, ephemeral: true})
ctx.client.users.fetch(user).then((user) => {
user.send({embeds: [dmEmbed]})
}).catch(() => console.log(`couldn't send a DM to user ID ${user}.`));
} else {
if (times.times > 2) {
const msg = await ctx.reply({content: `El usuario ha excedido 3 avisos, ¿qué hacer?`, ephemeral: true, components: [buttons]})
const collector = msg.createMessageComponentCollector({ time: 15000, max: 1, componentType: ComponentType.Button });
collector.on('collect', async (i) => {
await i.deferReply({ephemeral: true})
if (i.customId === '1hour') {
await i.editReply({content: `Se ha silenciado a ${usermember} durante 1 hora correctamente. ;-;`})
usermember.timeout(60 * 60 * 1000, reason)
times.times = 0
times.save()
} else if (i.customId === '30mins') {
await i.editReply({content: `Se ha silenciado a ${usermember} durante 30 minutos correctamente. ;-;`})
usermember.timeout(30 * 60 * 1000, reason)
times.times = 0
times.save()
} else if (i.customId === '15mins') {
await i.editReply({content: `Se ha silenciado a ${usermember} durante 15 minutos correctamente. ;-;`})
usermember.timeout(15 * 60 * 1000, reason)
times.times = 0
times.save()
} else if (i.customId === 'pardon') {
await i.editReply({content: `Se ha perdonado a ${usermember} correctamente.\nSeguro que la persona te lo agradecerá! :'D`})
times.times = 0
times.save()
}
ctx.client.users.fetch(user).then((user) => {
user.send({embeds: [dmEmbedTimeout]})
}).catch(() => console.log(`couldn't send a DM to user ID ${user}.`));
});
} else {
ctx.reply({content: `se ha añadido un aviso con el motivo ${reason}.\navisos que tiene ahora: ${times.times + 1}`, ephemeral: true})
times.times = times.times + 1
times.save()
ctx.client.users.fetch(user).then((user) => {
user.send({embeds: [dmEmbed]});
}).catch(() => console.log(`couldn't send a DM to user ID ${user}.`))
}
}
}
});
}
case "grave": {
return db.exists({id: `${user}`}, async function (err, doc) {
if (err) {
console.log(err)
} else {
if (doc === null) {
const warn = new db({id: `${user}`, times: 2})
warn.save()
ctx.reply({content: `Se ha avisado a ${usermember} correctamente y añadido a la base de datos.`, ephemeral: true})
ctx.client.users.fetch(user).then((user) => {
user.send({embeds: [dmEmbed]});
}).catch(() => console.log(`couldn't send a DM to user ID ${user}.`))
} else {
if (times.times >= 4) {
const msg = await ctx.reply({content: `El usuario ha excedido 3 avisos, ¿qué hacer?`, ephemeral: true, components: [buttons]})
const collector = msg.createMessageComponentCollector({ time: 1000, max: 1, componentType: ComponentType.Button });
collector.on('collect', async (i: any) => {
if (i.customId === '1hour') {
await i.channel!.send({content: `Se ha silenciado a ${usermember} durante 1 hora correctamente. ;-;`})
usermember.timeout(60 * 60 * 1000, reason)
times.times = 0
times.save()
} else if (i.customId === '30mins') {
await i.channel!.send({content: `Se ha silenciado a ${usermember} durante 30 minutos correctamente. ;-;`})
usermember.timeout(30 * 60 * 1000, reason)
times.times = 0
times.save()
} else if (i.customId === '15mins') {
await i.channel!.send({content: `Se ha silenciado a ${usermember} durante 15 minutos correctamente. ;-;`})
usermember.timeout(15 * 60 * 1000, reason)
times.times = 0
times.save()
} else if (i.customId === 'pardon') {
await i.channel!.send({content: `Se ha perdonado a ${usermember} correctamente.\nSeguro que la persona te lo agradecerá! :'D`})
times.times = 0
times.save()
}
ctx.client.users.fetch(user).then((user) => {
user.send({embeds: [dmEmbedTimeout]})
}).catch(() => console.log(`couldn't send a DM to user ID ${user}.`));
});
} else {
ctx.reply({content: `se ha añadido un aviso con el motivo ${reason}.\navisos que tiene ahora: ${times.times + 2}`, ephemeral: true})
times.times = times.times + 2
times.save()
ctx.client.users.fetch(user).then((user) => {
user.send({embeds: [dmEmbed]});
}).catch(() => console.log(`couldn't send a DM to user ID ${user}.`))
}
}
}
});
}
}
}
})

View File

@@ -1,15 +0,0 @@
import { commandModule, CommandType } from '@sern/handler'
import { publish } from "#plugins";
import { ownerOnly } from "#plugins"
export default commandModule({
name: 'ping',
type: CommandType.Slash,
plugins: [publish()],
description: 'A ping command',
//alias : [],
options: [],
execute: async (ctx, options) => {
await ctx.reply('Hello World!');
},
});

View File

@@ -1,10 +0,0 @@
#!/bin/bash
git pull
docker build . -t srizan10/vinci
docker stop vinci
docker rm vinci
docker run -d -t --name vinci -p 7272:7272 --restart unless-stopped srizan10/vinci

View File

@@ -1,25 +0,0 @@
import { EventType, eventModule } from '@sern/handler';
import { EmbedBuilder, Message } from 'discord.js';
import db from '../schemas/afk.js';
export default eventModule({
type: EventType.Discord,
name: 'messageCreate',
execute: async (message: Message) => {
const dbEntries = await db.find()
dbEntries.forEach(async (doc) => {
if (!message.content.includes(`<@${doc.id}`)) return;
if (message.author.bot) return;
const username = (await message.client.users.fetch(doc.id)).username
const embed = new EmbedBuilder()
.setColor('Red')
.setTitle(`Usuario ${username} está AFK`)
.setDescription(`El usuario que has mencionado en tu mensaje ha marcado su estado como AFK\nRazón: ${doc.reason}`)
.setFooter({ text: 'Este mensaje se eliminará en 10 segundos (wepa, como una bomba!)' })
const sentMessage = await message.reply({ embeds: [embed] })
setTimeout(async () => { await sentMessage.delete() }, 10_000)
})
},
});

View File

@@ -1,62 +0,0 @@
import { discordEvent } from '@sern/handler';
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, Message, TextChannel } from 'discord.js';
import tf from '@tensorflow/tfjs-node'
import axios from 'axios';
import { nsfwModel } from '../index.js';
export default discordEvent({
name: 'messageCreate',
execute(message: Message) {
message.attachments.forEach(async (attachment) => {
switch (attachment.contentType) {
case 'image/png':
break;
case 'image/jpeg':
break;
default:
return;
}
const pic = await axios.get(attachment.url,
{ responseType: 'arraybuffer' }
)
const image = tf.node.decodeImage(pic.data, 3) as tf.Tensor3D
// @ts-ignore
const predictions = await nsfwModel.classify(image)
switch (predictions[0].className) {
case 'Hentai':
case 'Porn':
if (predictions[0].probability > 0.75) {
const embed = new EmbedBuilder()
.setTitle(`Se ha detectado una imagen NSFW en tus adjuntos.`)
.setDescription('Por eso, se ha eliminado tu mensaje.\nPor si es un falso positivo, te vamos a dejar abajo el contenido del mensaje para recuperarlo.')
.setFields(
{ name: 'Contenido del mensaje', value: message.content || '(nada)' },
{ name: 'Tipo', value: predictions[0].className.toString() },
)
.setFooter({ text: 'Esta detección ha sido automatizada.' })
const modLogsEmbed = new EmbedBuilder()
.setAuthor({ name: message.author.username, iconURL: message.author.displayAvatarURL() })
.setTitle(`Se ha detectado una imagen NSFW en los adjuntos de un mensaje.`)
.setDescription('Aquí está toda la información:')
.setFields(
{ name: 'Contenido del mensaje', value: message.content || '(nada)' },
{ name: 'Tipo', value: predictions[0].className.toString() },
)
.setFooter({ text: 'Esta detección ha sido automatizada.' })
const button = new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setLabel('Imagen adjuntada que saltó las alarmas')
.setURL(attachment.url)
.setStyle(ButtonStyle.Link)
)
await message.delete()
await message.author.send({ embeds: [embed], components: [button] })
await (await message.client.channels.fetch(process.env.MODLOGS_CHANNEL!) as TextChannel).send({ embeds: [modLogsEmbed], components: [button] })
}
break;
}
})
},
});

View File

@@ -1,41 +0,0 @@
import { discordEvent } from '@sern/handler';
import axios from 'axios';
import { TextChannel } from 'discord.js';
import db from '../schemas/chatgpt.js';
export default discordEvent({
name: 'messageCreate',
async execute(message) {
if (message.channel.id !== process.env.CHATGPT_CHANNEL) return;
if (message.author.bot) return;
if (message.content.includes('ig')) return;
try {
await (message.channel as TextChannel).sendTyping()
const response = await axios.post('https://chatgpt-api.shn.hk/v1/', {
"model": "gpt-3.5-turbo",
"messages": [{ "role": "user", "content": message.content }]
}).then(res => res.data)
const titleResponse = await axios.post('https://chatgpt-api.shn.hk/v1/', {
"model": "gpt-3.5-turbo",
"messages": [{ "role": "user", "content": `Generate a title in less than 6 words for the following message, also remove the quotes if you are going to add them AND don't put Title in the beginning:\nUser: ${message.content}\nAssistant: ${response.choices[0].message.content}` }]
}).then(res => res.data.choices[0].message.content.replaceAll('"', '') as string)
const botMsg = await message.reply({ content: response.choices[0].message.content.slice(0, 2000) })
const thread = await botMsg.startThread({ name: titleResponse })
const dbData = new db({
messageid: message.id,
threadid: thread.id,
messages: [
{ role: 'user', content: message.content },
{ role: 'assistant', content: response.choices[0].message.content.replace(/^\n{2}/, '') }
]
})
await dbData.save()
} catch (e) {
await message.reply({ content: 'Algo ha ido mal.' }).catch(() => {})
console.log(e)
}
},
});

View File

@@ -1,53 +0,0 @@
import { discordEvent } from '@sern/handler';
import axios from 'axios';
import { ThreadChannel } from 'discord.js';
import database from '../schemas/chatgpt.js';
export default discordEvent({
name: 'messageCreate',
async execute(message) {
const thread = message.channel as ThreadChannel
if (thread.parentId !== process.env.CHATGPT_CHANNEL) return;
if (message.author.bot) return;
if (message.content.includes('ig')) return;
try {
await thread.sendTyping()
let newObj = { role: 'user', content: message.content }
let db = await database.findOneAndUpdate({ threadid: thread.id }, {
$push: {
messages: newObj
}
})
const messages = db!.messages.map((message) => {
const { _id, ...rest } = message.toObject(); // Convert Mongoose document to plain object and remove _id field
return rest
})
const response = await axios.post('https://chatgpt-api.shn.hk/v1/', {
"model": "gpt-3.5-turbo",
"messages": messages
}, {
headers: {
'Content-Type': 'application/json'
}
}).then(res => res.data.choices[0].message.content as string)
newObj = { role: 'assistant', content: response }
db = await database.findOneAndUpdate({ threadid: thread.id }, {
$push: {
messages: newObj
}
})
await message.reply({ content: response.slice(0, 2000) })
} catch (e) {
await message.reply('Algo ha ido mal.')
console.log(e)
}
},
});
function replacer(key, value) {
return value.replace(/[^\w\s]/gi, '');
}

View File

@@ -1,9 +0,0 @@
import { EventType, eventModule } from "@sern/handler";
export default eventModule({
type: EventType.Sern,
name : 'error',
execute(err) {
console.log(err);
}
})

View File

@@ -1,20 +0,0 @@
import { EmbedBuilder, GuildMember, TextChannel } from "discord.js";
import { EventType, eventModule } from "@sern/handler";
export default eventModule({
type: EventType.Discord,
name: 'guildMemberAdd',
execute(member: GuildMember) {
if (member.guild.id !== process.env.GUILDID) return;
const newMemberEmbed = new EmbedBuilder()
.setColor("Random")
.setTitle("Nuevo miembro!")
.setDescription(`${member.user} acaba de entrar al servidor!`)
.setThumbnail(member.user.displayAvatarURL())
.setTimestamp();
const channel = member.client.guilds.cache.get(process.env.GUILDID!)!.channels.cache.get(process.env.JOINSANDLEAVES_CHANNEL!) as TextChannel
channel.send({embeds: [newMemberEmbed]})
}
});

View File

@@ -1,20 +0,0 @@
import { EmbedBuilder, GuildMember, TextChannel } from "discord.js";
import { EventType, eventModule } from "@sern/handler";
export default eventModule({
type: EventType.Discord,
name: 'guildMemberRemove',
execute(member: GuildMember) {
if (member.guild.id !== process.env.GUILDID) return;
const leaveEmbed = new EmbedBuilder()
.setColor("Random")
.setTitle("Un miembro se ha ido :(")
.setDescription(`${member.user} acaba de salir del servidor!`)
.setThumbnail(member.user.displayAvatarURL())
.setTimestamp();
const channel = member.client.guilds.cache.get(process.env.GUILDID!)!.channels.cache.get(process.env.JOINSANDLEAVES_CHANNEL!) as TextChannel
channel.send({embeds: [leaveEmbed]})
}
});

View File

@@ -1,53 +0,0 @@
import { discordEvent } from '@sern/handler';
import {
ActionRowBuilder,
ButtonBuilder,
ButtonStyle,
EmbedBuilder,
TextChannel,
} from 'discord.js';
import { scamLinks } from '../index.js';
export default discordEvent({
name: 'messageCreate',
async execute(message) {
if (!message.content.includes('https://')) return;
const index = message.content.indexOf("https://");
let link = 'some goofy ahh string that is gonna be replaced'
if (index !== -1) {
let endIndex = message.content.indexOf(" ", index);
if (endIndex === -1) {
endIndex = message.content.length;
}
link = message.content.substring(index, endIndex);
}
const url = new URL(link);
if (scamLinks.includes(url.hostname)) {
const embed = new EmbedBuilder()
.setTitle(`Se ha detectado un enlace scam en tu mensaje.`)
.setDescription('Por eso, se ha eliminado tu mensaje.\nPor si es un falso positivo, te vamos a dejar abajo el contenido del mensaje para recuperarlo.')
.setFields(
{ name: 'Contenido del mensaje', value: message.content || '(nada)' },
)
.setFooter({ text: 'Esta detección ha sido automatizada por Vinci.' })
const modLogsEmbed = new EmbedBuilder()
.setTitle(`Se ha detectado un enlace scam el mensaje de un usuario.`)
.setDescription('Por eso, se ha eliminado el mensaje.')
.setFields(
{ name: 'Contenido del mensaje', value: message.content || '(nada)' },
)
.setFooter({ text: 'Esta detección ha sido automatizada por Vinci.' })
const button = new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setLabel('Enlace que saltó las alarmas.')
.setURL(link)
.setStyle(ButtonStyle.Link)
)
await message.delete()
await message.author.send({ embeds: [embed], components: [button] })
await (await message.client.channels.fetch(process.env.MODLOGS_CHANNEL!) as TextChannel).send({ embeds: [modLogsEmbed], components: [button] })
}
},
});

View File

@@ -1,95 +0,0 @@
import { DefaultLogging, Dependencies, single, Singleton } from '@sern/handler';
import { ActivityType } from 'discord.js';
import { Client, GatewayIntentBits } from 'discord.js';
import { Sern } from '@sern/handler';
import { config as dotenv } from 'dotenv';
import mongoose from 'mongoose';
import youtubenotifications from './util/youtubenotifications.js';
import { setIntervalAsync } from 'set-interval-async';
import birthdays from './util/birthdays.js';
import minecraftstatus from './util/minecraftstatus.js';
import axios from 'axios';
// import giveawaychecker from './util/giveawaychecker.js';
let devMode: boolean
if (process.argv[2] === '--dev') {
devMode = true
dotenv({path: '.env.dev'})
console.clear()
} else {
dotenv()
}
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildMembers,
GatewayIntentBits.MessageContent,
GatewayIntentBits.GuildMembers,
GatewayIntentBits.GuildMessageReactions,
GatewayIntentBits.GuildVoiceStates,
],
});
mongoose.connect(process.env.MONGODB!).then(() => {
console.log('Connected to MongoDB');
});
interface MyDependencies extends Dependencies {
'@sern/client' : Singleton<Client>;
'@sern/logger' : Singleton<DefaultLogging>
}
export const useContainer = Sern.makeDependencies<MyDependencies>({
build: root => root
.add({ '@sern/client': single(client) })
.upsert({ '@sern/logger': single(new DefaultLogging()) })
});
Sern.init({
commands: 'dist/commands',
events: 'dist/events',
defaultPrefix: process.env.PREFIX,
containerConfig: {
get: useContainer
}
});
client.on('ready', async () => {
console.log('Logged on!');
setInterval(() => {
const statuses = [
{ name: 'Minecraft', type: ActivityType.Playing },
{ name: 'cómo escribe Javi', type: ActivityType.Watching },
{ name: 'quinto libro when', type: ActivityType.Watching },
{ name: 'a Hermes', type: ActivityType.Watching },
{ name: 'tus comandos', type: ActivityType.Listening },
{ name: 'tu voz', type: ActivityType.Listening },
{ name: 'ahora v1.0!', type: ActivityType.Playing },
];
const randomStatus = statuses[Math.floor(Math.random() * statuses.length)];
// @ts-ignore
client.user!.setActivity(randomStatus);
}, 10000);
if (!devMode) {
setIntervalAsync(async () => {
await youtubenotifications(client);
}, 120_000);
setIntervalAsync(async () => {
await birthdays(client);
}, 3_600_000);
setIntervalAsync(async () => {
await minecraftstatus(client);
}, 20_000);
} else {
console.log('DevMode got activated, there are no checkers in this version.')
}
});
export const scamLinks = await axios.get('https://api.hyperphish.com/gimme-domains').then(res => res.data as Array<string>)
client.login(process.env.TOKEN);

1
nixpacks.toml Normal file
View File

@@ -0,0 +1 @@
providers = ["node", "python"]

View File

@@ -1,66 +1,44 @@
{
"name": "vinci",
"version": "1.0.0",
"description": "Vinci Discord Bot for Mara Turing",
"main": "dist/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "tsc-watch --onSuccess \"node ./dist/index.js --dev\"",
"compile": "tsc --build",
"build": "tsc --build",
"web": "node webserver.js",
"watch": "tsc --watch",
"start": "nodemon dist/index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/SrIzan10/vinci.git"
},
"imports": {
"#plugins": [
"./dist/plugins/index.js"
]
},
"keywords": [
"discord-bot"
],
"type": "module",
"author": "Sr Izan",
"license": "MIT",
"bugs": {
"url": "https://github.com/SrIzan10/vinci/issues"
},
"homepage": "https://github.com/SrIzan10/vinci#readme",
"dependencies": {
"@consumet/extensions": "1.3.5",
"@discordjs/opus": "^0.9.0",
"@discordjs/voice": "^0.15.0",
"@napi-rs/canvas": "^0.1.30",
"@sern/handler": "^2.5.3",
"axios": "^1.1.3",
"dayjs": "^1.11.6",
"discord-tictactoe": "^4.0.0",
"discord.js": "^14.7.1",
"dotenv": "^16.0.1",
"execa": "^6.1.0",
"express": "^4.18.1",
"form-data": "^4.0.0",
"genius-lyrics": "^4.4.3",
"googlethis": "^1.7.1",
"got": "^12.5.3",
"libsodium-wrappers": "^0.7.10",
"mongoose": "^6.11.3",
"node-fetch": "^3.3.1",
"pretty-seconds-spanish": "^2.1.1",
"rockpaperscissors-checker": "^1.2.0",
"set-interval-async": "^3.0.2",
"stringify-safe": "^1.0.3",
"systeminformation": "^5.12.6"
},
"devDependencies": {
"@types/express": "^4.17.14",
"ts-node": "10.9.1",
"tsc-watch": "^5.0.3",
"typescript": "^4.9.3"
}
"name": "ts-example",
"version": "1.0.0",
"private": true,
"description": "",
"main": "dist/index.js",
"scripts": {
"build": "sern build",
"start": "bun run --inspect .",
"db:migrate": "prisma migrate deploy",
"install": "sern build",
"commands:publish": "sern commands publish",
"dev": "sern build -w --watch-command \"bun start\"",
"db:mongo": "bun run src/utils/db/migrateMongo.ts"
},
"keywords": [
"typescript",
"sern",
"discord.js"
],
"dependencies": {
"@napi-rs/canvas": "^0.1.72",
"@prisma/client": "^6.10.1",
"@sern/handler": "^4.2.4",
"@sern/publisher": "1.1.2",
"discord.js": "^14.21.0",
"dotenv": "^16.3.1",
"execa": "^9.6.0",
"mongodb": "^6.17.0",
"node-html-parser": "^7.0.1",
"openai": "^5.10.2",
"rockpaperscissors-checker": "^1.2.0",
"sharp": "^0.34.2"
},
"devDependencies": {
"@sern/cli": "^1.4.0",
"@types/bun": "^1.2.18",
"@types/mongodb": "^4.0.7",
"@types/node": "^17.0.25",
"prisma": "^6.10.1",
"typescript": "^5.0"
},
"type": "module"
}

View File

@@ -1,107 +0,0 @@
//@ts-nocheck
/**
* This is buttonConfirmation plugin, it runs confirmation prompt in the form of buttons.
* Note that you need to use edit/editReply in the command itself because we are already replying in the plugin!
* Credits to original plugin of confirmation using reactions and its author!
*
* @author @EvolutionX-10 [<@697795666373640213>]
* @version 1.0.0
* @example
* ```ts
* import { buttonConfirmation } from "../plugins/buttonConfirmation";
* import { commandModule } from "@sern/handler";
* export default commandModule({
* plugins: [ buttonConfirmation() ],
* execute: (ctx) => {
* //your code here
* }
* })
* ```
*/
import { CommandControlPlugin, CommandType, controller } from "@sern/handler";
import {
ActionRowBuilder,
ButtonBuilder,
ButtonStyle,
ComponentType,
} from "discord.js";
export function acceptingBirthday(options?: Partial<ConfirmationOptions>) {
return CommandControlPlugin<CommandType.Both>(async (ctx, args) => {
options = {
content: "Se va a guardar tu cumpleaños en la base de datos de Vinci.\nAceptas?",
denialMessage: "Ok pues...",
labels: ["No", "Sí"],
time: 60_000,
wrongUserResponse: "Esto no es para tí!",
...options,
};
const buttons = options.labels!.map((l, i) => {
return new ButtonBuilder()
.setCustomId(l)
.setLabel(l)
.setStyle(
i === 0 ? ButtonStyle.Danger : ButtonStyle.Success
);
});
const sent = await ctx.reply({
content: options.content,
components: [
new ActionRowBuilder<ButtonBuilder>().setComponents(
buttons
),
],
ephemeral: true
});
const collector = sent.createMessageComponentCollector({
componentType: ComponentType.Button,
filter: (i) => i.user.id === ctx.user.id,
time: options.time,
});
return new Promise((resolve) => {
collector.on("collect", async (i) => {
await i.update({ components: [] });
collector.stop();
if (i.customId === options!.labels![1]) {
resolve(controller.next());
return;
}
await i.editReply({
content: options?.denialMessage,
});
resolve(controller.stop());
});
collector.on("end", async (c) => {
if (c.size) return;
buttons.forEach((b) => b.setDisabled());
await sent.edit({
components: [
new ActionRowBuilder<ButtonBuilder>().setComponents(
buttons
),
],
});
});
collector.on("ignore", async (i) => {
await i.reply({
content: options?.wrongUserResponse,
ephemeral: true,
});
});
});
});
}
interface ConfirmationOptions {
content: string;
denialMessage: string;
time: number;
labels: [string, string];
wrongUserResponse: string;
}

View File

@@ -1,4 +0,0 @@
export * from './publish.js'
export * from './ownerOnly.js'
export * from './srIzanOnly.js'
export * from './acceptingBirthday.js'

View File

@@ -1,29 +0,0 @@
// @ts-nocheck
/**
* This is OwnerOnly plugin, it allows only bot owners to run the command, like eval.
*
* @author @EvolutionX-10 [<@697795666373640213>]
* @version 1.0.0
* @example
* ```ts
* import { ownerOnly } from "../plugins/ownerOnly";
* import { commandModule } from "@sern/handler";
* export default commandModule({
* plugins: [ ownerOnly() ],
* execute: (ctx) => {
* //your code here
* }
* })
* ```
*/
import { CommandType, CommandControlPlugin, controller } from "@sern/handler";
const ownerIDs = ["464397024247152640", "703974042700611634", '252679156465139722', '370918560446545922', '375984365181599744', '785836117630910485', '368107342140801025']; //! Fill your ID
export function ownerOnly() {
return CommandControlPlugin<CommandType.Both>((ctx, args) => {
if (ownerIDs.includes(ctx.user.id)) return controller.next();
//* If you want to reply when the command fails due to user not being owner, you can use following
ctx.reply("**ERROR**: Sólo los administradores pueden correr este comando.");
return controller.stop(); //! Important: It stops the execution of command!
});
}

View File

@@ -1,196 +0,0 @@
// @ts-nocheck
/**
* This is publish plugin, it allows you to publish your application commands using the discord.js library with ease.
*
* @author @EvolutionX-10 [<@697795666373640213>]
* @version 2.0.0
* @example
* ```ts
* import { publish } from "../plugins/publish";
* import { commandModule } from "@sern/handler";
* export default commandModule({
* plugins: [ publish() ], // put an object containing permissions, ids for guild commands, boolean for dmPermission
* // plugins: [ publish({ guildIds: ['guildId'], defaultMemberPermissions: 'Administrator'})]
* execute: (ctx) => {
* //your code here
* }
* })
* ```
*/
import {
CommandInitPlugin,
CommandType,
controller,
SernOptionsData,
SlashCommand,
} from "@sern/handler";
import {
ApplicationCommandData,
ApplicationCommandType,
PermissionResolvable,
} from "discord.js";
import { useContainer } from "../index.js";
export const CommandTypeRaw = {
[CommandType.Both]: ApplicationCommandType.ChatInput,
[CommandType.CtxUser]: ApplicationCommandType.User,
[CommandType.CtxMsg]: ApplicationCommandType.Message,
[CommandType.Slash]: ApplicationCommandType.ChatInput,
} as const;
export function publish<
T extends
| CommandType.Both
| CommandType.Slash
| CommandType.CtxMsg
| CommandType.CtxUser
>(options?: PublishOptions) {
return CommandInitPlugin<T>(async ({ module }) => {
// Users need to provide their own useContainer function.
const [client] = useContainer("@sern/client");
const defaultOptions = {
guildIds: [],
dmPermission: undefined,
defaultMemberPermissions: null,
};
options = { ...defaultOptions, ...options } as PublishOptions &
ValidPublishOptions;
let { defaultMemberPermissions, dmPermission, guildIds } =
options as unknown as ValidPublishOptions;
function c(e: unknown) {
console.error("publish command didnt work for", module.name);
console.error(e);
}
const log =
(...message: any[]) =>
() =>
console.log(...message);
const logged = (...message: any[]) => log(message);
/**
* a local function that returns either one value or the other,
* depending on {t}'s CommandType. If the commandtype of
* this module is CommandType.Both or CommandType.Text or CommandType.Slash,
* return 'is', else return 'els'
* @param t
* @returns S | T
*/
const appCmd = <V extends CommandType, S, T>(t: V) => {
return (is: S, els: T) => ((t & CommandType.Both) !== 0 ? is : els);
};
const curAppType = CommandTypeRaw[module.type];
const createCommandData = () => {
const cmd = appCmd(module.type);
return {
name: module.name,
type: curAppType,
description: cmd(module.description, ""),
options: cmd(
optionsTransformer((module as SlashCommand).options ?? []),
[]
),
defaultMemberPermissions,
dmPermission,
} as ApplicationCommandData;
};
try {
const commandData = createCommandData();
if (!guildIds.length) {
const cmd = (await client.application!.commands.fetch()).find(
(c) => c.name === module.name && c.type === curAppType
);
if (cmd) {
if (!cmd.equals(commandData, true)) {
logged(
`Found differences in global command ${module.name}`
);
cmd.edit(commandData).then(
log(
`${module.name} updated with new data successfully!`
)
);
}
return controller.next();
}
client
.application!.commands.create(commandData)
.then(log("Command created", module.name))
.catch(c);
return controller.next();
}
for (const id of guildIds) {
const guild = await client.guilds.fetch(id).catch(c);
if (!guild) continue;
const guildCmd = (await guild.commands.fetch()).find(
(c) => c.name === module.name && c.type === curAppType
);
if (guildCmd) {
if (!guildCmd.equals(commandData, true)) {
logged(`Found differences in command ${module.name}`);
guildCmd
.edit(commandData)
.then(
log(
`${module.name} updated with new data successfully!`
)
)
.catch(c);
continue;
}
continue;
}
guild.commands
.create(commandData)
.then(log("Guild Command created", module.name, guild.name))
.catch(c);
}
return controller.next();
} catch (e) {
logged("Command did not register" + module.name);
logged(e);
return controller.stop();
}
});
}
export function optionsTransformer(ops: Array<SernOptionsData>) {
return ops.map((el) =>
el.autocomplete ? (({ command, ...el }) => el)(el) : el
);
}
export type NonEmptyArray<T extends `${number}` = `${number}`> = [T, ...T[]];
export interface ValidPublishOptions {
guildIds: string[];
dmPermission: boolean;
defaultMemberPermissions: PermissionResolvable;
}
interface GuildPublishOptions {
guildIds?: NonEmptyArray;
defaultMemberPermissions?: PermissionResolvable;
dmPermission?: never;
}
interface GlobalPublishOptions {
defaultMemberPermissions?: PermissionResolvable;
dmPermission?: false;
guildIds?: never;
}
type BasePublishOptions = GuildPublishOptions | GlobalPublishOptions;
export type PublishOptions = BasePublishOptions &
(
| Required<Pick<BasePublishOptions, "defaultMemberPermissions">>
| (
| Required<Pick<BasePublishOptions, "dmPermission">>
| Required<Pick<BasePublishOptions, "guildIds">>
)
);

View File

@@ -1,29 +0,0 @@
// @ts-nocheck
/**
* This is OwnerOnly plugin, it allows only bot owners to run the command, like eval.
*
* @author @EvolutionX-10 [<@697795666373640213>]
* @version 1.0.0
* @example
* ```ts
* import { ownerOnly } from "../plugins/ownerOnly";
* import { commandModule } from "@sern/handler";
* export default commandModule({
* plugins: [ ownerOnly() ],
* execute: (ctx) => {
* //your code here
* }
* })
* ```
*/
import { CommandType, CommandControlPlugin, controller } from "@sern/handler";
const ownerIDs = ['703974042700611634']; //! Fill your ID
export function srIzanOnly() {
return CommandControlPlugin<CommandType.Both>((ctx, args) => {
if (ownerIDs.includes(ctx.user.id)) return controller.next();
//* If you want to reply when the command fails due to user not being owner, you can use following
ctx.reply("**ERROR**: Sólo Sr Izan puede correr este comando.");
return controller.stop(); //! Important: It stops the execution of command!
});
}

View File

@@ -0,0 +1,15 @@
-- CreateTable
CREATE TABLE "ai_chats" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"messageid" TEXT NOT NULL,
"threadid" TEXT NOT NULL
);
-- CreateTable
CREATE TABLE "AIMessage" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"role" TEXT NOT NULL,
"content" TEXT NOT NULL,
"aiChatId" INTEGER NOT NULL,
CONSTRAINT "AIMessage_aiChatId_fkey" FOREIGN KEY ("aiChatId") REFERENCES "ai_chats" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);

View File

@@ -0,0 +1,19 @@
/*
Warnings:
- You are about to drop the `AIMessage` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropTable
PRAGMA foreign_keys=off;
DROP TABLE "AIMessage";
PRAGMA foreign_keys=on;
-- CreateTable
CREATE TABLE "AiMessage" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"role" TEXT NOT NULL,
"content" TEXT NOT NULL,
"aiChatId" INTEGER NOT NULL,
CONSTRAINT "AiMessage_aiChatId_fkey" FOREIGN KEY ("aiChatId") REFERENCES "ai_chats" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);

View File

@@ -0,0 +1,33 @@
/*
Warnings:
- You are about to drop the `ai_chats` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropTable
PRAGMA foreign_keys=off;
DROP TABLE "ai_chats";
PRAGMA foreign_keys=on;
-- CreateTable
CREATE TABLE "AiChat" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"messageid" TEXT NOT NULL,
"threadid" TEXT NOT NULL
);
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_AiMessage" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"role" TEXT NOT NULL,
"content" TEXT NOT NULL,
"aiChatId" INTEGER NOT NULL,
CONSTRAINT "AiMessage_aiChatId_fkey" FOREIGN KEY ("aiChatId") REFERENCES "AiChat" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_AiMessage" ("aiChatId", "content", "id", "role") SELECT "aiChatId", "content", "id", "role" FROM "AiMessage";
DROP TABLE "AiMessage";
ALTER TABLE "new_AiMessage" RENAME TO "AiMessage";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,10 @@
-- CreateTable
CREATE TABLE "Afk" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"userId" TEXT NOT NULL,
"reason" TEXT NOT NULL,
"expiresAt" DATETIME NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "Afk_userId_key" ON "Afk"("userId");

View File

@@ -0,0 +1,12 @@
/*
Warnings:
- A unique constraint covering the columns `[messageid]` on the table `AiChat` will be added. If there are existing duplicate values, this will fail.
- A unique constraint covering the columns `[threadid]` on the table `AiChat` will be added. If there are existing duplicate values, this will fail.
*/
-- CreateIndex
CREATE UNIQUE INDEX "AiChat_messageid_key" ON "AiChat"("messageid");
-- CreateIndex
CREATE UNIQUE INDEX "AiChat_threadid_key" ON "AiChat"("threadid");

View File

@@ -0,0 +1,20 @@
/*
Warnings:
- You are about to drop the column `expiresAt` on the `Afk` table. All the data in the column will be lost.
*/
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_Afk" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"userId" TEXT NOT NULL,
"reason" TEXT NOT NULL
);
INSERT INTO "new_Afk" ("id", "reason", "userId") SELECT "id", "reason", "userId" FROM "Afk";
DROP TABLE "Afk";
ALTER TABLE "new_Afk" RENAME TO "Afk";
CREATE UNIQUE INDEX "Afk_userId_key" ON "Afk"("userId");
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,10 @@
-- CreateTable
CREATE TABLE "Birthday" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"userId" TEXT NOT NULL,
"date" TEXT NOT NULL,
"sent" BOOLEAN NOT NULL DEFAULT false
);
-- CreateIndex
CREATE UNIQUE INDEX "Birthday_userId_key" ON "Birthday"("userId");

View File

@@ -0,0 +1,12 @@
-- CreateTable
CREATE TABLE "Suggestion" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"userId" TEXT NOT NULL,
"msgId" TEXT NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "Suggestion_userId_key" ON "Suggestion"("userId");
-- CreateIndex
CREATE UNIQUE INDEX "Suggestion_msgId_key" ON "Suggestion"("msgId");

View File

@@ -0,0 +1,22 @@
/*
Warnings:
- Added the required column `upDown` to the `Suggestion` table without a default value. This is not possible if the table is not empty.
*/
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_Suggestion" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"userId" TEXT NOT NULL,
"msgId" TEXT NOT NULL,
"upDown" INTEGER NOT NULL
);
INSERT INTO "new_Suggestion" ("id", "msgId", "userId") SELECT "id", "msgId", "userId" FROM "Suggestion";
DROP TABLE "Suggestion";
ALTER TABLE "new_Suggestion" RENAME TO "Suggestion";
CREATE UNIQUE INDEX "Suggestion_userId_key" ON "Suggestion"("userId");
CREATE UNIQUE INDEX "Suggestion_msgId_key" ON "Suggestion"("msgId");
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,2 @@
-- DropIndex
DROP INDEX "Suggestion_userId_key";

View File

@@ -0,0 +1,2 @@
-- DropIndex
DROP INDEX "Suggestion_msgId_key";

View File

@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "sqlite"

52
prisma/schema.prisma Normal file
View File

@@ -0,0 +1,52 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
generator client {
provider = "prisma-client-js"
binaryTargets = ["native", "debian-openssl-3.0.x"]
}
datasource db {
provider = "sqlite"
url = "file:./vinci.db"
}
model AiChat {
id Int @id @default(autoincrement())
messageid String @unique
threadid String @unique
messages AiMessage[]
}
model AiMessage {
id Int @id @default(autoincrement())
role String
content String
aiChatId Int
aiChat AiChat @relation(fields: [aiChatId], references: [id])
}
model Afk {
id Int @id @default(autoincrement())
userId String @unique
reason String
}
model Birthday {
id Int @id @default(autoincrement())
userId String @unique
date String
sent Boolean @default(false)
}
model Suggestion {
id Int @id @default(autoincrement())
userId String
msgId String
upDown Int
}

View File

@@ -1,7 +0,0 @@
import mongoose from 'mongoose'
const schema = new mongoose.Schema({
id: {type: String, required: true},
reason: {type: String, required: true},
});
const db = mongoose.model('afk', schema, 'afk');
export default db

View File

@@ -1,8 +0,0 @@
import mongoose from 'mongoose'
const schema = new mongoose.Schema({
id: {type: String, required: true},
date: {type: String, required: true},
alreadysent: {type: Boolean, required: true},
});
const db = mongoose.model('birthday', schema, 'birthdays');
export default db

View File

@@ -1,12 +0,0 @@
import mongoose from 'mongoose'
const messageSchema = new mongoose.Schema({
role: { type: String, required: true },
content: { type: String, required: true },
});
const schema = new mongoose.Schema({
messageid: { type: String, required: true },
threadid: { type: String, required: true },
messages: { type: [messageSchema], required: true },
});
const db = mongoose.model('chatgpt', schema, 'chatgpt');
export default db

View File

@@ -1,9 +0,0 @@
const mongoose = require('mongoose');
const schema = new mongoose.Schema({
number: {type: Number, required: true}
})
const db = new mongoose.Model('counting', schema)
module.exports = db;

Some files were not shown because too many files have changed in this diff Show More