Compare commits
29 Commits
custom-vc
...
decouple-r
| Author | SHA1 | Date | |
|---|---|---|---|
| 13fd3d5812 | |||
| e4425b23be | |||
| fc8f90a4bc | |||
| 330aabd928 | |||
| dfb8b2781d | |||
| 5271665963 | |||
| dd7553f294 | |||
| 73b1d82f43 | |||
| b138b8378b | |||
| f20bdde4e6 | |||
| 93788b9873 | |||
| 0e014dd08d | |||
| 331fea2c10 | |||
| 58426ca45d | |||
| bc0a6f2526 | |||
| 453577f1b2 | |||
| d2e88f15ea | |||
|
|
0cb5a02b28 | ||
| 43a7ee75a2 | |||
| ca4b64bde1 | |||
| 0a460800b6 | |||
| 84b851f60f | |||
| 7678c1a722 | |||
| 6053692bc1 | |||
| cb7235fd69 | |||
| aa88d30244 | |||
| 071fe2f891 | |||
|
|
b3766b9584 | ||
| 6ce1fdf67d |
@@ -1,48 +0,0 @@
|
|||||||
name: release-tag
|
|
||||||
|
|
||||||
on: push
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release-image:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: catthehacker/ubuntu:act-latest
|
|
||||||
# env:
|
|
||||||
# DOCKER_ORG: teacup
|
|
||||||
# DOCKER_LATEST: nightly
|
|
||||||
# RUNNER_TOOL_CACHE: /toolcache
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v2
|
|
||||||
|
|
||||||
- name: Set up Docker BuildX
|
|
||||||
uses: docker/setup-buildx-action@v2
|
|
||||||
|
|
||||||
- name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: git.unom.io # replace it with your local IP
|
|
||||||
username: ${{ vars.DOCKER_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKER_TOKEN }}
|
|
||||||
|
|
||||||
- name: Get Meta
|
|
||||||
id: meta
|
|
||||||
run: |
|
|
||||||
echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}') >> $GITHUB_OUTPUT
|
|
||||||
echo REPO_VERSION=$(git describe --tags --always | sed 's/^v//') >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v4
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: ./Dockerfile
|
|
||||||
platforms: |
|
|
||||||
linux/amd64
|
|
||||||
linux/arm64
|
|
||||||
push: true
|
|
||||||
tags: | # replace it with your local IP and tags
|
|
||||||
git.unom.io/mo/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }}
|
|
||||||
git.unom.io/mo/${{ steps.meta.outputs.REPO_NAME }}:latest
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -177,3 +177,6 @@ dist
|
|||||||
# DB
|
# DB
|
||||||
avocadis_diary.sqlite
|
avocadis_diary.sqlite
|
||||||
prod.sqlite
|
prod.sqlite
|
||||||
|
|
||||||
|
# vscode specific setttings
|
||||||
|
.vscode/
|
||||||
36
adapters/discord/.gitignore
vendored
Normal file
36
adapters/discord/.gitignore
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# dependencies (bun install)
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# output
|
||||||
|
out
|
||||||
|
dist
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# code coverage
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# logs
|
||||||
|
logs
|
||||||
|
_.log
|
||||||
|
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.local
|
||||||
|
.env.dev
|
||||||
|
.env.prod
|
||||||
|
|
||||||
|
# caches
|
||||||
|
.eslintcache
|
||||||
|
.cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# IntelliJ based IDEs
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Finder (MacOS) folder config
|
||||||
|
.DS_Store
|
||||||
106
adapters/discord/CLAUDE.md
Normal file
106
adapters/discord/CLAUDE.md
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
|
||||||
|
Default to using Bun instead of Node.js.
|
||||||
|
|
||||||
|
- Use `bun <file>` instead of `node <file>` or `ts-node <file>`
|
||||||
|
- Use `bun test` instead of `jest` or `vitest`
|
||||||
|
- Use `bun build <file.html|file.ts|file.css>` instead of `webpack` or `esbuild`
|
||||||
|
- Use `bun install` instead of `npm install` or `yarn install` or `pnpm install`
|
||||||
|
- Use `bun run <script>` instead of `npm run <script>` or `yarn run <script>` or `pnpm run <script>`
|
||||||
|
- Use `bunx <package> <command>` instead of `npx <package> <command>`
|
||||||
|
- Bun automatically loads .env, so don't use dotenv.
|
||||||
|
|
||||||
|
## APIs
|
||||||
|
|
||||||
|
- `Bun.serve()` supports WebSockets, HTTPS, and routes. Don't use `express`.
|
||||||
|
- `bun:sqlite` for SQLite. Don't use `better-sqlite3`.
|
||||||
|
- `Bun.redis` for Redis. Don't use `ioredis`.
|
||||||
|
- `Bun.sql` for Postgres. Don't use `pg` or `postgres.js`.
|
||||||
|
- `WebSocket` is built-in. Don't use `ws`.
|
||||||
|
- Prefer `Bun.file` over `node:fs`'s readFile/writeFile
|
||||||
|
- Bun.$`ls` instead of execa.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
Use `bun test` to run tests.
|
||||||
|
|
||||||
|
```ts#index.test.ts
|
||||||
|
import { test, expect } from "bun:test";
|
||||||
|
|
||||||
|
test("hello world", () => {
|
||||||
|
expect(1).toBe(1);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Frontend
|
||||||
|
|
||||||
|
Use HTML imports with `Bun.serve()`. Don't use `vite`. HTML imports fully support React, CSS, Tailwind.
|
||||||
|
|
||||||
|
Server:
|
||||||
|
|
||||||
|
```ts#index.ts
|
||||||
|
import index from "./index.html"
|
||||||
|
|
||||||
|
Bun.serve({
|
||||||
|
routes: {
|
||||||
|
"/": index,
|
||||||
|
"/api/users/:id": {
|
||||||
|
GET: (req) => {
|
||||||
|
return new Response(JSON.stringify({ id: req.params.id }));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// optional websocket support
|
||||||
|
websocket: {
|
||||||
|
open: (ws) => {
|
||||||
|
ws.send("Hello, world!");
|
||||||
|
},
|
||||||
|
message: (ws, message) => {
|
||||||
|
ws.send(message);
|
||||||
|
},
|
||||||
|
close: (ws) => {
|
||||||
|
// handle close
|
||||||
|
}
|
||||||
|
},
|
||||||
|
development: {
|
||||||
|
hmr: true,
|
||||||
|
console: true,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
HTML files can import .tsx, .jsx or .js files directly and Bun's bundler will transpile & bundle automatically. `<link>` tags can point to stylesheets and Bun's CSS bundler will bundle.
|
||||||
|
|
||||||
|
```html#index.html
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<h1>Hello, world!</h1>
|
||||||
|
<script type="module" src="./frontend.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
With the following `frontend.tsx`:
|
||||||
|
|
||||||
|
```tsx#frontend.tsx
|
||||||
|
import React from "react";
|
||||||
|
import { createRoot } from "react-dom/client";
|
||||||
|
|
||||||
|
// import .css files directly and it works
|
||||||
|
import './index.css';
|
||||||
|
|
||||||
|
const root = createRoot(document.body);
|
||||||
|
|
||||||
|
export default function Frontend() {
|
||||||
|
return <h1>Hello, world!</h1>;
|
||||||
|
}
|
||||||
|
|
||||||
|
root.render(<Frontend />);
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, run index.ts
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bun --hot ./index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information, read the Bun API docs in `node_modules/bun-types/docs/**.mdx`.
|
||||||
15
adapters/discord/README.md
Normal file
15
adapters/discord/README.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# discord
|
||||||
|
|
||||||
|
To install dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
To run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
This project was created using `bun init` in bun v1.3.5. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
|
||||||
26
adapters/discord/bun.lock
Normal file
26
adapters/discord/bun.lock
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"configVersion": 1,
|
||||||
|
"workspaces": {
|
||||||
|
"": {
|
||||||
|
"name": "discord",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="],
|
||||||
|
|
||||||
|
"@types/node": ["@types/node@25.2.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ=="],
|
||||||
|
|
||||||
|
"bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="],
|
||||||
|
|
||||||
|
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||||
|
|
||||||
|
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
||||||
|
}
|
||||||
|
}
|
||||||
30
adapters/discord/package.json
Normal file
30
adapters/discord/package.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "@avocadi/bot-adapter-discord",
|
||||||
|
"type": "module",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsdown",
|
||||||
|
"dev:prod": "tsdown --watch & NODE_ENV=production node --watch ./dist/index.js",
|
||||||
|
"dev": "tsdown --watch & NODE_ENV=development node --watch ./dist/index.js"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"tsdown": "catalog:"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@avocadi/bot-core": "workspace:*",
|
||||||
|
"@discordjs/rest": "^2.6.0",
|
||||||
|
"cron": "^4.4.0",
|
||||||
|
"discord.js": "^14.25.1",
|
||||||
|
"dotenv": "^17.3.1",
|
||||||
|
"dotenv-expand": "^12.0.3",
|
||||||
|
"zod": "catalog:"
|
||||||
|
},
|
||||||
|
"exports": {
|
||||||
|
".": "./dist/index.js",
|
||||||
|
"./package.json": "./package.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
19
adapters/discord/src/actions/publish-commands.ts
Normal file
19
adapters/discord/src/actions/publish-commands.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { config } from "config";
|
||||||
|
import { Routes } from "discord.js";
|
||||||
|
import getCommands from "entities/commands";
|
||||||
|
import { logger } from "lib/common-logger";
|
||||||
|
import { discordRestClient } from "lib/rest-client";
|
||||||
|
|
||||||
|
export const publishCommands = async () => {
|
||||||
|
try {
|
||||||
|
await discordRestClient.put(
|
||||||
|
Routes.applicationCommands(config.discord.applicationId),
|
||||||
|
{
|
||||||
|
body: getCommands(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
logger.info("successfully added commands");
|
||||||
|
} catch (e) {
|
||||||
|
logger.error("failed to add commands:", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
7
adapters/discord/src/actions/shutdown.ts
Normal file
7
adapters/discord/src/actions/shutdown.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { logChannelService } from "features/log-channel/log-channel.service";
|
||||||
|
import { logger } from "lib/common-logger";
|
||||||
|
|
||||||
|
export const handleShutdown = async () => {
|
||||||
|
logger.info("bot is shutting down...");
|
||||||
|
await logChannelService.sendLogMessage("**S H U T T I N G D O W N**");
|
||||||
|
};
|
||||||
24
adapters/discord/src/config/config.schema.ts
Normal file
24
adapters/discord/src/config/config.schema.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import {
|
||||||
|
TextChannels,
|
||||||
|
VoiceChannels,
|
||||||
|
} from "@avocadi/bot-core/entities/channels/channels.schema";
|
||||||
|
import { Roles } from "@avocadi/bot-core/entities/roles/roles.schema";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export const ConfigSchema = z.object({
|
||||||
|
channelMapping: z.object({
|
||||||
|
text: z.record(TextChannels, z.string()),
|
||||||
|
voice: z.record(VoiceChannels, z.string()),
|
||||||
|
}),
|
||||||
|
roleMapping: z.record(Roles, z.string()),
|
||||||
|
reactionRoles: z.object({
|
||||||
|
allowedMessageIds: z.array(z.string()),
|
||||||
|
}),
|
||||||
|
guildId: z.string(),
|
||||||
|
version: z.number(),
|
||||||
|
commandPrefix: z.string().default("!"),
|
||||||
|
discord: z.object({
|
||||||
|
token: z.string(),
|
||||||
|
applicationId: z.string(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
6
adapters/discord/src/config/env/env.schema.ts
vendored
Normal file
6
adapters/discord/src/config/env/env.schema.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export const EnvSchema = z.object({
|
||||||
|
DISCORD_APPLICATION_ID: z.string(),
|
||||||
|
DISCORD_TOKEN: z.string(),
|
||||||
|
});
|
||||||
29
adapters/discord/src/config/env/index.ts
vendored
Normal file
29
adapters/discord/src/config/env/index.ts
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import { join } from "node:path";
|
||||||
|
import dotenv from "dotenv";
|
||||||
|
import dotenvExpand from "dotenv-expand";
|
||||||
|
import { EnvSchema } from "./env.schema";
|
||||||
|
|
||||||
|
const envFile =
|
||||||
|
process.env.NODE_ENV === "production" ? ".env.prod" : ".env.dev";
|
||||||
|
|
||||||
|
const envPath = join(process.cwd(), envFile);
|
||||||
|
|
||||||
|
const rawEnv = Buffer.from(
|
||||||
|
readFileSync(envPath, {
|
||||||
|
encoding: "utf8",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const envJson = { processEnv: dotenv.parse(rawEnv) };
|
||||||
|
|
||||||
|
const targetObj = {};
|
||||||
|
|
||||||
|
const expandedEnv = dotenvExpand.expand({
|
||||||
|
processEnv: targetObj,
|
||||||
|
parsed: envJson.processEnv,
|
||||||
|
}) as { processEnv: Record<string, string> };
|
||||||
|
|
||||||
|
const env = EnvSchema.parse(expandedEnv.processEnv);
|
||||||
|
|
||||||
|
export default env;
|
||||||
49
adapters/discord/src/config/index.ts
Normal file
49
adapters/discord/src/config/index.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import type z from "zod";
|
||||||
|
import type { ConfigSchema } from "./config.schema";
|
||||||
|
import env from "./env";
|
||||||
|
|
||||||
|
export const config: z.output<typeof ConfigSchema> = {
|
||||||
|
channelMapping: {
|
||||||
|
text: {
|
||||||
|
bot: "1317253291633279026",
|
||||||
|
log: "1321972449365065728",
|
||||||
|
bump: "1330310075759329412",
|
||||||
|
feedback: "1321626600185266176",
|
||||||
|
help: "1321860125127872605",
|
||||||
|
introduction: "1321473655523246171",
|
||||||
|
news: "1321953521435934741",
|
||||||
|
general: "1316153372507639855",
|
||||||
|
rules: "1316153372507639849",
|
||||||
|
testing: "1451310086864507112",
|
||||||
|
welcome: "1316153372507639852",
|
||||||
|
pomodoro: "1369718059824054483",
|
||||||
|
},
|
||||||
|
voice: {
|
||||||
|
custom: "1451323742805561457",
|
||||||
|
"for-four": "1321563441588207727",
|
||||||
|
"for-group": "1321607205207805992",
|
||||||
|
"for-three": "1321563403952721970",
|
||||||
|
"for-two": "1316153372755234858",
|
||||||
|
"pomodoro-25-5": "1369717999061438504",
|
||||||
|
"pomodoro-50-10": "1370518840114544814",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
roleMapping: {
|
||||||
|
admin: "1321467874220576778",
|
||||||
|
mention: "1332478785731428372",
|
||||||
|
mod: "1321468169608757350",
|
||||||
|
people: "1321470720424939662",
|
||||||
|
bot: "1321491461111283722",
|
||||||
|
},
|
||||||
|
reactionRoles: {
|
||||||
|
allowedMessageIds: [
|
||||||
|
"1321491461111283722", // Example message ID for reaction roles
|
||||||
|
],
|
||||||
|
},
|
||||||
|
guildId: "1316153371899592774",
|
||||||
|
version: 1,
|
||||||
|
discord: {
|
||||||
|
token: env.DISCORD_TOKEN,
|
||||||
|
applicationId: env.DISCORD_APPLICATION_ID,
|
||||||
|
},
|
||||||
|
};
|
||||||
61
adapters/discord/src/discord.controller.ts
Normal file
61
adapters/discord/src/discord.controller.ts
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import EventEmitter from "node:events";
|
||||||
|
import {
|
||||||
|
type WaterMeController,
|
||||||
|
waterMeController,
|
||||||
|
} from "features/water-me/water-me.controller";
|
||||||
|
import client from "lib/client";
|
||||||
|
|
||||||
|
export default class DiscordController extends EventEmitter {
|
||||||
|
async handleChatInputCommand(
|
||||||
|
interaction: ChatInputCommandInteraction<CacheType>,
|
||||||
|
) {
|
||||||
|
const commandName = interaction.commandName as CommandsType;
|
||||||
|
|
||||||
|
// add commands
|
||||||
|
switch (commandName) {
|
||||||
|
case Commands.Enum.giessen:
|
||||||
|
await this.waterMeService.handleInteraction(interaction); // zu chatinputcommand wechseln
|
||||||
|
return;
|
||||||
|
case Commands.Enum.medikamente:
|
||||||
|
await this.medicationService.handleChatInputCommand(interaction);
|
||||||
|
return;
|
||||||
|
case Commands.Enum.hilfe:
|
||||||
|
await this.helpService.handleInteraction(interaction); // zu chatinputcommand wechseln
|
||||||
|
return;
|
||||||
|
case Commands.Enum.support:
|
||||||
|
case Commands.Enum.kofi:
|
||||||
|
case Commands.Enum.disboard:
|
||||||
|
case Commands.Enum.discadia:
|
||||||
|
await this.supportService.handleInteraction(interaction);
|
||||||
|
return;
|
||||||
|
case Commands.Enum.accept:
|
||||||
|
await this.greetingService.handleChatInputCommand(interaction);
|
||||||
|
return;
|
||||||
|
case Commands.Enum.welcome:
|
||||||
|
await this.greetingService.handleChatInputCommand(interaction);
|
||||||
|
return;
|
||||||
|
case Commands.Enum.embed:
|
||||||
|
case Commands.Enum.message:
|
||||||
|
await this.customMessageService.handleChatInputCommand(interaction);
|
||||||
|
return;
|
||||||
|
case Commands.Enum.reminder:
|
||||||
|
await this.greetingService.handleChatInputCommand(interaction);
|
||||||
|
return;
|
||||||
|
case Commands.Enum.version:
|
||||||
|
await this.debugService.handleChatInputCommand(interaction);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// wenn neues fenster durch buttonclick or so
|
||||||
|
async handleModalSubmit(interaction: ModalSubmitInteraction<CacheType>) {
|
||||||
|
const { customId } = interaction;
|
||||||
|
|
||||||
|
switch (customId) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import type { VoiceChannelsServiceInterface } from "@avocadi/bot-core/entities/channels/voice/voice-channels.service";
|
||||||
|
import { config } from "config";
|
||||||
|
import { ChannelType, type User, type VoiceChannel } from "discord.js";
|
||||||
|
import client from "lib/client";
|
||||||
|
import { logger } from "lib/common-logger";
|
||||||
|
|
||||||
|
export class VoiceChannelsService
|
||||||
|
implements VoiceChannelsServiceInterface<VoiceChannel>
|
||||||
|
{
|
||||||
|
/***
|
||||||
|
*/
|
||||||
|
async getVoiceChannelById(channelId: string) {
|
||||||
|
const channel = await client.channels.fetch(channelId);
|
||||||
|
|
||||||
|
if (!channel) {
|
||||||
|
logger.error(`Channel with id ${channelId} not found`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channel.type !== ChannelType.GuildVoice) {
|
||||||
|
logger.error(`Channel with id ${channelId} is not a voice channel`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
async createVoiceChannel(name: string) {
|
||||||
|
const guild = await client.guilds.fetch(config.guildId);
|
||||||
|
const channel = await guild.channels.create({
|
||||||
|
name,
|
||||||
|
type: ChannelType.GuildVoice,
|
||||||
|
});
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
async cloneVoiceChannel(
|
||||||
|
user_id: string,
|
||||||
|
channel: VoiceChannel,
|
||||||
|
options?: { name?: string; position?: number },
|
||||||
|
) {
|
||||||
|
const clonedChannel = await channel.clone({
|
||||||
|
name: options?.name,
|
||||||
|
position: options?.position,
|
||||||
|
permissionOverwrites: [
|
||||||
|
{
|
||||||
|
id: user_id,
|
||||||
|
allow: ["ManageChannels"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
return clonedChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteVoiceChannel(channelId: string) {
|
||||||
|
const channel = await this.getVoiceChannelById(channelId);
|
||||||
|
|
||||||
|
if (!channel) return;
|
||||||
|
await channel.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const voiceChannelsService = new VoiceChannelsService();
|
||||||
32
adapters/discord/src/entities/commands/index.ts
Normal file
32
adapters/discord/src/entities/commands/index.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { CommandsCollection } from "@avocadi/bot-core/entities/commands/commands.entity";
|
||||||
|
import type { Command } from "@avocadi/bot-core/entities/commands/commands.schema";
|
||||||
|
import { SlashCommandBuilder } from "discord.js";
|
||||||
|
import type { z } from "zod";
|
||||||
|
|
||||||
|
const convertCommandToDiscordFormat = (
|
||||||
|
command: z.output<typeof Command>,
|
||||||
|
key: string,
|
||||||
|
) => {
|
||||||
|
const slashCommand = new SlashCommandBuilder()
|
||||||
|
.setName(command.name || key)
|
||||||
|
.setDescription(command.description);
|
||||||
|
|
||||||
|
if (command.options) {
|
||||||
|
command.options.forEach((option) => {
|
||||||
|
slashCommand.addStringOption((opt) =>
|
||||||
|
opt
|
||||||
|
.setName(option.name)
|
||||||
|
.setDescription(option.description)
|
||||||
|
.setRequired(option.required),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return slashCommand;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function getCommands() {
|
||||||
|
return Object.entries(CommandsCollection).map(([key, command]) =>
|
||||||
|
convertCommandToDiscordFormat(command, key),
|
||||||
|
);
|
||||||
|
}
|
||||||
78
adapters/discord/src/entities/messages/messages.service.ts
Normal file
78
adapters/discord/src/entities/messages/messages.service.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import type { MessagesServiceInterface } from "@avocadi/bot-core/entities/messages/messages.service";
|
||||||
|
import { createLogger } from "@avocadi/bot-core/lib/logger";
|
||||||
|
import {
|
||||||
|
type Channel,
|
||||||
|
ChannelType,
|
||||||
|
type DMChannel,
|
||||||
|
type Message,
|
||||||
|
type MessagePayload,
|
||||||
|
type PartialDMChannel,
|
||||||
|
type User,
|
||||||
|
} from "discord.js";
|
||||||
|
import { logChannelService } from "features/log-channel/log-channel.service";
|
||||||
|
import client from "lib/client";
|
||||||
|
|
||||||
|
export class MessagesService
|
||||||
|
implements MessagesServiceInterface<User, Message, Channel, MessagePayload>
|
||||||
|
{
|
||||||
|
private logger = createLogger("MessagesService");
|
||||||
|
|
||||||
|
async sendToUser(userInput: User, message: MessagePayload): Promise<void> {
|
||||||
|
const user = await client.users.fetch(userInput.id);
|
||||||
|
|
||||||
|
if (!user) this.logger.error(`User with ID ${userInput.id} not found.`);
|
||||||
|
this.logger.info(`sending message to user with ID ${userInput.id}.`);
|
||||||
|
await user.send(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
async logMessage(message: Message): Promise<void> {
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
message.channel.isDMBased() &&
|
||||||
|
message.channel.type !== ChannelType.GroupDM
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
const channel = message.channel as DMChannel | PartialDMChannel;
|
||||||
|
|
||||||
|
const recipient = channel.recipient?.id;
|
||||||
|
|
||||||
|
let logMessage: string;
|
||||||
|
|
||||||
|
if (message.author.bot) {
|
||||||
|
logMessage = `<@${message.author.id}> hat an <@${recipient}> geschrieben:\n"${message.content}"`;
|
||||||
|
} else {
|
||||||
|
logMessage = `<@${message.author.id}> hat geschrieben:\n"${message.content}"`;
|
||||||
|
}
|
||||||
|
|
||||||
|
await logChannelService.sendLogMessage(logMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendToChannel(
|
||||||
|
channel: Channel,
|
||||||
|
createMessageInput: MessagePayload,
|
||||||
|
): Promise<void> {
|
||||||
|
const fetchedChannel = await client.channels.fetch(channel.id);
|
||||||
|
|
||||||
|
if (fetchedChannel?.isTextBased() && fetchedChannel.isSendable()) {
|
||||||
|
this.logger.info(`sending message to channel with ID ${channel.id}.`);
|
||||||
|
const success = await fetchedChannel.send(createMessageInput);
|
||||||
|
if (success)
|
||||||
|
this.logger.info(
|
||||||
|
`sending message to channel with ID ${channel.id} SUCCESS.`,
|
||||||
|
);
|
||||||
|
else
|
||||||
|
this.logger.error(
|
||||||
|
`sending message to channel with ID ${channel.id} FAILED.`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.logger.error(
|
||||||
|
`Channel with ID ${channel.id} not found or is not text-based.`,
|
||||||
|
);
|
||||||
|
|
||||||
|
throw new Error("Channel not found or is not text-based.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const messagesService = new MessagesService();
|
||||||
38
adapters/discord/src/entities/roles/roles.service.ts
Normal file
38
adapters/discord/src/entities/roles/roles.service.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import type { RolesServiceInterface } from "@avocadi/bot-core/entities/roles/roles.service";
|
||||||
|
import { createLogger } from "@avocadi/bot-core/lib/logger";
|
||||||
|
import type { GuildMember } from "discord.js";
|
||||||
|
|
||||||
|
export class RolesService implements RolesServiceInterface<GuildMember> {
|
||||||
|
private logger = createLogger("RolesService");
|
||||||
|
|
||||||
|
async assignRole(user: GuildMember, roleId: string) {
|
||||||
|
const roleToAssign = user.guild.roles.cache.find((r) => r.id === roleId);
|
||||||
|
if (!roleToAssign) {
|
||||||
|
this.logger.error(
|
||||||
|
`Role ${roleId} not found in guild ${user.guild.name}.`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.logger.info(`Role ${roleId} found in guild ${user.guild.name}.`);
|
||||||
|
await user.roles.add(roleToAssign);
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeRole(user: GuildMember, role: string) {
|
||||||
|
const roleToRemove = user.guild.roles.cache.find((r) => r.name === role);
|
||||||
|
if (!roleToRemove) {
|
||||||
|
this.logger.error(`Role ${role} not found in guild ${user.guild.name}.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await user.roles.remove(roleToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** get all roles of GuildMember */
|
||||||
|
async getRoles(user: GuildMember) {
|
||||||
|
return user.roles.cache.map((role) => role.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** check if GuildMember has a specific role */
|
||||||
|
async hasRole(user: GuildMember, role: string) {
|
||||||
|
return user.roles.cache.some((r) => r.name === role);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { AcceptUserService } from "@avocadi/bot-core/features/accept-user/accept-user.service";
|
||||||
|
import { i18nService } from "@avocadi/bot-core/lib/i18n";
|
||||||
|
import type { User } from "discord.js";
|
||||||
|
import { messagesService } from "entities/messages/messages.service";
|
||||||
|
|
||||||
|
export const acceptUserService = new AcceptUserService<User>(
|
||||||
|
messagesService,
|
||||||
|
i18nService,
|
||||||
|
"de",
|
||||||
|
);
|
||||||
19
adapters/discord/src/features/activity/activity.schema.ts
Normal file
19
adapters/discord/src/features/activity/activity.schema.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export const Activities = z.enum([
|
||||||
|
"playing",
|
||||||
|
"streaming",
|
||||||
|
"listening",
|
||||||
|
"watching",
|
||||||
|
"competing",
|
||||||
|
"invisible",
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const ActivityLocales: Record<z.infer<typeof Activities>, string> = {
|
||||||
|
playing: "spielt sudoku",
|
||||||
|
streaming: "streamt sudoku",
|
||||||
|
listening: "hoert sudoku",
|
||||||
|
watching: "schaut sudoku",
|
||||||
|
competing: "wettstreitet sudoku",
|
||||||
|
invisible: "versteckt sudoku",
|
||||||
|
};
|
||||||
27
adapters/discord/src/features/activity/activity.service.ts
Normal file
27
adapters/discord/src/features/activity/activity.service.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import client from "lib/client";
|
||||||
|
import type z from "zod";
|
||||||
|
import { type Activities, ActivityLocales } from "./activity.schema";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the activity of the bot. This can be used to show that the bot is playing a game, listening to music, etc.
|
||||||
|
*/
|
||||||
|
export class ActivityService {
|
||||||
|
async set(activity: z.output<typeof Activities>) {
|
||||||
|
if (activity === "invisible") {
|
||||||
|
client.user?.setPresence({
|
||||||
|
status: "invisible",
|
||||||
|
});
|
||||||
|
client.user?.setActivity(" ", { type: 0 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.user?.setActivity(ActivityLocales[activity], {
|
||||||
|
type: 0,
|
||||||
|
});
|
||||||
|
client.user?.setPresence({
|
||||||
|
status: "online",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const activityService = new ActivityService();
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { VoiceChannels } from "@avocadi/bot-core/entities/channels/channels.schema";
|
||||||
|
import { DynamicVoiceChannelsService } from "@avocadi/bot-core/features/dynamic-voice-channels/dynamic-voice-channels.service";
|
||||||
|
import { config } from "config";
|
||||||
|
import { voiceChannelsService } from "entities/channels/voice/voice-channels.service";
|
||||||
|
|
||||||
|
export const dynamicVoiceChannelService = new DynamicVoiceChannelsService(
|
||||||
|
voiceChannelsService,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
channelId: config.channelMapping.voice["for-two"],
|
||||||
|
key: VoiceChannels.enum["for-two"],
|
||||||
|
size: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channelId: config.channelMapping.voice["for-three"],
|
||||||
|
key: VoiceChannels.enum["for-three"],
|
||||||
|
size: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channelId: config.channelMapping.voice["for-four"],
|
||||||
|
key: VoiceChannels.enum["for-four"],
|
||||||
|
size: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channelId: config.channelMapping.voice["for-group"],
|
||||||
|
key: VoiceChannels.enum["for-group"],
|
||||||
|
size: 99,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channelId: config.channelMapping.voice.custom,
|
||||||
|
key: VoiceChannels.enum.custom,
|
||||||
|
size: 99,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
);
|
||||||
10
adapters/discord/src/features/greeting/greeting.service.ts
Normal file
10
adapters/discord/src/features/greeting/greeting.service.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { GreetingService } from "@avocadi/bot-core/features/greeting/greeting.service";
|
||||||
|
import { i18nService } from "@avocadi/bot-core/lib/i18n";
|
||||||
|
import type { Channel, Message, User } from "discord.js";
|
||||||
|
import { messagesService } from "entities/messages/messages.service";
|
||||||
|
|
||||||
|
export const greetingService = new GreetingService<User, Message, Channel>(
|
||||||
|
messagesService,
|
||||||
|
i18nService,
|
||||||
|
"de",
|
||||||
|
);
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { config } from "config";
|
||||||
|
import client from "lib/client";
|
||||||
|
import { logger } from "lib/common-logger";
|
||||||
|
|
||||||
|
export class LogChannelService {
|
||||||
|
private logChannelId =
|
||||||
|
process.env.NODE_ENV === "production"
|
||||||
|
? config.channelMapping.text.log
|
||||||
|
: config.channelMapping.text.testing;
|
||||||
|
|
||||||
|
async getLogChannel() {
|
||||||
|
const logChannel = await client.channels.fetch(this.logChannelId);
|
||||||
|
|
||||||
|
if (logChannel?.isTextBased() && logChannel.isSendable()) {
|
||||||
|
return logChannel;
|
||||||
|
} else {
|
||||||
|
logger.fatal("Log channel not found or is not text-based.");
|
||||||
|
throw new Error("Log channel not found or is not text-based");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendLogMessage(message: string) {
|
||||||
|
const logChannel = await this.getLogChannel();
|
||||||
|
|
||||||
|
await logChannel.send(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const logChannelService = new LogChannelService();
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
import type { Roles } from "@avocadi/bot-core/entities/roles/roles.schema";
|
||||||
|
import { createLogger } from "@avocadi/bot-core/lib/logger";
|
||||||
|
import { config } from "config";
|
||||||
|
import type {
|
||||||
|
GuildMember,
|
||||||
|
MessageReaction,
|
||||||
|
PartialMessageReaction,
|
||||||
|
PartialUser,
|
||||||
|
User,
|
||||||
|
} from "discord.js";
|
||||||
|
import type z from "zod";
|
||||||
|
|
||||||
|
export class ReactionRolesService {
|
||||||
|
private logger = createLogger("ReactionRolesService");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method validates if the reaction is on an allowed message for reaction roles.
|
||||||
|
* @param reaction
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async validateReaction(reaction: MessageReaction | PartialMessageReaction) {
|
||||||
|
this.logger.info(
|
||||||
|
`Validating reaction ${reaction.emoji.name} on message ${reaction.message.id}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const message = await reaction.message.fetch();
|
||||||
|
|
||||||
|
if (!message) {
|
||||||
|
this.logger.error(`Message with ID ${reaction.message.id} not found.`);
|
||||||
|
return;
|
||||||
|
// throw new Error("Message not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.reactionRoles.allowedMessageIds.includes(message.id)) {
|
||||||
|
this.logger.error(
|
||||||
|
`Message with ID ${message.id} is not allowed for reaction roles.`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
// throw new Error("Message not allowed for reaction roles");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a reaction, validates it, and assigns or removes the given role.
|
||||||
|
* @param reaction
|
||||||
|
* @param guild
|
||||||
|
* @param user
|
||||||
|
* @param role
|
||||||
|
*/
|
||||||
|
async handleReaction(
|
||||||
|
reaction: MessageReaction | PartialMessageReaction,
|
||||||
|
user: User | PartialUser,
|
||||||
|
targetRole: z.output<typeof Roles>,
|
||||||
|
action: "add" | "remove",
|
||||||
|
) {
|
||||||
|
const guild = reaction.message.guild;
|
||||||
|
|
||||||
|
if (!guild) {
|
||||||
|
this.logger.error(`Guild not found for message ${reaction.message.id}.`);
|
||||||
|
throw new Error("Guild not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.validateReaction(reaction);
|
||||||
|
|
||||||
|
const role = guild.roles.cache.get(config.roleMapping[targetRole]);
|
||||||
|
|
||||||
|
if (!role) {
|
||||||
|
this.logger.error(`Role ${targetRole} not found in guild ${guild.name}.`);
|
||||||
|
throw new Error("Role not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const member = await guild.members.fetch(user.id);
|
||||||
|
|
||||||
|
if (!member) {
|
||||||
|
this.logger.error(
|
||||||
|
`User with ID ${user.id} not found in guild ${guild.name}.`,
|
||||||
|
);
|
||||||
|
throw new Error("User not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (member.roles.cache.has(role.id)) {
|
||||||
|
if (action === "remove") {
|
||||||
|
this.removeRoleByReaction(reaction, member, targetRole);
|
||||||
|
} else {
|
||||||
|
this.logger.info(
|
||||||
|
`User ${member.user.tag} already has role ${targetRole}. No action taken.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === "remove") {
|
||||||
|
this.logger.info(
|
||||||
|
`User ${member.user.tag} does not have role ${targetRole}. No action taken.`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.assignRoleByReaction(reaction, member, targetRole);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
async assignRoleByReaction(
|
||||||
|
reaction: MessageReaction | PartialMessageReaction,
|
||||||
|
member: GuildMember,
|
||||||
|
role: z.output<typeof Roles>,
|
||||||
|
) {
|
||||||
|
this.logger.info(
|
||||||
|
`Assigning role ${role} based on reaction ${reaction.emoji.name} by user ${member.user.tag}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
await member.roles.add(config.roleMapping[role]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeRoleByReaction(
|
||||||
|
reaction: MessageReaction | PartialMessageReaction,
|
||||||
|
member: GuildMember,
|
||||||
|
role: z.output<typeof Roles>,
|
||||||
|
) {
|
||||||
|
this.logger.info(
|
||||||
|
`Removing role ${role} based on reaction ${reaction.emoji.name} by user ${member.user.tag}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
await member.roles.remove(config.roleMapping[role]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import type { WaterMeService } from "@avocadi/bot-core/features/water-me/water-me.service";
|
||||||
|
import {
|
||||||
|
ActionRowBuilder,
|
||||||
|
ButtonBuilder,
|
||||||
|
type ButtonInteraction,
|
||||||
|
ButtonStyle,
|
||||||
|
type ChatInputCommandInteraction,
|
||||||
|
} from "discord.js";
|
||||||
|
import { waterMeService } from "./water-me.service";
|
||||||
|
|
||||||
|
class WaterMeController {
|
||||||
|
waterMeService: WaterMeService;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.waterMeService = waterMeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleInteraction(
|
||||||
|
interaction: ButtonInteraction | ChatInputCommandInteraction,
|
||||||
|
) {
|
||||||
|
const result = this.waterMeService.waterMe();
|
||||||
|
|
||||||
|
const moreButton = new ButtonBuilder()
|
||||||
|
.setCustomId("moreWater")
|
||||||
|
.setLabel("mehr")
|
||||||
|
.setStyle(ButtonStyle.Secondary);
|
||||||
|
|
||||||
|
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(moreButton);
|
||||||
|
|
||||||
|
if (interaction.isChatInputCommand()) {
|
||||||
|
await interaction.reply({
|
||||||
|
content: result.reply,
|
||||||
|
components: [row],
|
||||||
|
});
|
||||||
|
} else if (interaction.isButton()) {
|
||||||
|
await interaction.reply({
|
||||||
|
content: result.reply,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const waterMeController = new WaterMeController();
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { WaterMeService } from "@avocadi/bot-core/features/water-me/water-me.service";
|
||||||
|
import { i18nService } from "@avocadi/bot-core/lib/i18n";
|
||||||
|
import { messagesService } from "entities/messages/messages.service";
|
||||||
|
|
||||||
|
export const waterMeService = new WaterMeService(
|
||||||
|
messagesService,
|
||||||
|
i18nService,
|
||||||
|
"de",
|
||||||
|
);
|
||||||
12
adapters/discord/src/features/water-me/water-me.tasks.ts
Normal file
12
adapters/discord/src/features/water-me/water-me.tasks.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { CronJob } from "cron";
|
||||||
|
import { waterMeService } from "./water-me.service";
|
||||||
|
|
||||||
|
new CronJob(
|
||||||
|
"0 0 20 * * *", // cronTime
|
||||||
|
async () => {
|
||||||
|
await waterMeService.notifyIfThirsty();
|
||||||
|
}, // onTick
|
||||||
|
null, // onComplete
|
||||||
|
true, // start
|
||||||
|
"Europe/Berlin", // timeZone
|
||||||
|
);
|
||||||
5
adapters/discord/src/index.ts
Normal file
5
adapters/discord/src/index.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { publishCommands } from "actions/publish-commands";
|
||||||
|
import "./listeners";
|
||||||
|
|
||||||
|
// Publish commands when the application starts
|
||||||
|
await publishCommands();
|
||||||
24
adapters/discord/src/lib/client.ts
Normal file
24
adapters/discord/src/lib/client.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { config } from "config";
|
||||||
|
import { Client, IntentsBitField, Partials } from "discord.js";
|
||||||
|
|
||||||
|
const client = new Client({
|
||||||
|
intents: [
|
||||||
|
IntentsBitField.Flags.Guilds,
|
||||||
|
IntentsBitField.Flags.GuildMembers,
|
||||||
|
IntentsBitField.Flags.GuildModeration,
|
||||||
|
IntentsBitField.Flags.GuildMessages,
|
||||||
|
IntentsBitField.Flags.GuildMessageReactions,
|
||||||
|
IntentsBitField.Flags.GuildMessagePolls,
|
||||||
|
IntentsBitField.Flags.GuildVoiceStates,
|
||||||
|
IntentsBitField.Flags.MessageContent,
|
||||||
|
IntentsBitField.Flags.DirectMessages,
|
||||||
|
IntentsBitField.Flags.DirectMessageReactions,
|
||||||
|
IntentsBitField.Flags.DirectMessageTyping,
|
||||||
|
IntentsBitField.Flags.DirectMessagePolls,
|
||||||
|
],
|
||||||
|
partials: [Partials.Channel, Partials.Message, Partials.Reaction],
|
||||||
|
});
|
||||||
|
|
||||||
|
await client.login(config.discord.token);
|
||||||
|
|
||||||
|
export default client;
|
||||||
3
adapters/discord/src/lib/common-logger.ts
Normal file
3
adapters/discord/src/lib/common-logger.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { createLogger } from "@avocadi/bot-core/lib/logger";
|
||||||
|
|
||||||
|
export const logger = createLogger("DiscordAdapter");
|
||||||
6
adapters/discord/src/lib/rest-client.ts
Normal file
6
adapters/discord/src/lib/rest-client.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { REST } from "@discordjs/rest";
|
||||||
|
import { config } from "config";
|
||||||
|
|
||||||
|
export const discordRestClient = new REST({ version: "10" }).setToken(
|
||||||
|
config.discord.token,
|
||||||
|
);
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { i18nService } from "@avocadi/bot-core/lib/i18n";
|
||||||
|
import { config } from "config";
|
||||||
|
import { greetingService } from "features/greeting/greeting.service";
|
||||||
|
import { logChannelService } from "features/log-channel/log-channel.service";
|
||||||
|
import client from "lib/client";
|
||||||
|
import { logger } from "lib/common-logger";
|
||||||
|
|
||||||
|
client.on("guildMemberAdd", async (member) => {
|
||||||
|
if (member.user.bot) {
|
||||||
|
// Don't send a welcome message for bots (sorry tom)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const channel = await member.guild.channels.fetch(
|
||||||
|
config.channelMapping.text.welcome,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!channel) return;
|
||||||
|
|
||||||
|
greetingService.sendGreeting(member.user.id, channel);
|
||||||
|
greetingService.sendDmGreeting(member.user);
|
||||||
|
|
||||||
|
// logChannelService.sendLogMessage(await i18nService.t("greeting1", "de", "greeting"), TODO
|
||||||
|
});
|
||||||
7
adapters/discord/src/listeners/index.ts
Normal file
7
adapters/discord/src/listeners/index.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import "./ready.listener";
|
||||||
|
import "./stop.listener";
|
||||||
|
import "./guild-members/guild-members.listener";
|
||||||
|
import "./voice-state/voice-state.listener";
|
||||||
|
import "./interactions/interactions.listener";
|
||||||
|
import "./reactions/reactions.listener";
|
||||||
|
import "./messages/messages.listener";
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import type { ButtonInteraction } from "discord.js";
|
||||||
|
import { waterMeController } from "features/water-me/water-me.controller";
|
||||||
|
|
||||||
|
export const handleButtonInteraction = async (
|
||||||
|
interaction: ButtonInteraction,
|
||||||
|
) => {
|
||||||
|
waterMeController.handleInteraction(interaction);
|
||||||
|
};
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import type { ChatInputCommandInteraction } from "discord.js";
|
||||||
|
import { waterMeController } from "features/water-me/water-me.controller";
|
||||||
|
|
||||||
|
export const handleChatInputCommandInteraction = async (
|
||||||
|
interaction: ChatInputCommandInteraction,
|
||||||
|
) => {
|
||||||
|
waterMeController.handleInteraction(interaction);
|
||||||
|
};
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import type { ModalSubmitInteraction } from "discord.js";
|
||||||
|
|
||||||
|
export const handleModalSubmitInteraction = async (
|
||||||
|
interaction: ModalSubmitInteraction,
|
||||||
|
) => {};
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import client from "lib/client";
|
||||||
|
import { logger } from "lib/common-logger";
|
||||||
|
import { handleButtonInteraction } from "./handle-button";
|
||||||
|
import { handleChatInputCommandInteraction } from "./handle-chat-input-command";
|
||||||
|
import { handleModalSubmitInteraction } from "./handle-modal-submit";
|
||||||
|
|
||||||
|
client.on("interactionCreate", async (interaction) => {
|
||||||
|
if (interaction.isModalSubmit()) {
|
||||||
|
logger.debug("isModalSubmit");
|
||||||
|
await handleModalSubmitInteraction(interaction);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interaction.isChatInputCommand()) {
|
||||||
|
logger.debug("isChatInputCommand");
|
||||||
|
await handleChatInputCommandInteraction(interaction);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (interaction.isCommand()) {
|
||||||
|
logger.debug("isCommand");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (interaction.isButton()) {
|
||||||
|
logger.debug("isButton");
|
||||||
|
await handleButtonInteraction(interaction);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
74
adapters/discord/src/listeners/messages/messages.listener.ts
Normal file
74
adapters/discord/src/listeners/messages/messages.listener.ts
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
import { CommandKeys } from "@avocadi/bot-core/entities/commands/commands.schema";
|
||||||
|
import { config } from "config";
|
||||||
|
import type { Message } from "discord.js";
|
||||||
|
import { messagesService } from "entities/messages/messages.service";
|
||||||
|
import client from "lib/client";
|
||||||
|
import { logger } from "lib/common-logger";
|
||||||
|
|
||||||
|
client.on("messageCreate", async (message: Message) => {
|
||||||
|
if (message.channel.isDMBased()) {
|
||||||
|
await messagesService.logMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.content?.startsWith(config.commandPrefix) && message.channel) {
|
||||||
|
await recognizedCommand(message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function recognizedCommand(message: Message) {
|
||||||
|
if (!resolveModContext(message)) return;
|
||||||
|
await messagesService.logMessage(message);
|
||||||
|
logger.info(
|
||||||
|
`Command received: ${message.content} from user ${message.author.id}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const commandWithoutPrefix = message.content
|
||||||
|
.slice(config.commandPrefix.length)
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
const commandParts = commandWithoutPrefix.split(" ");
|
||||||
|
|
||||||
|
if (commandParts.length === 0) {
|
||||||
|
logger.warn("No command found after prefix.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [command, ...parameters] = commandParts;
|
||||||
|
|
||||||
|
logger.info(`Parsed command: ${command}`);
|
||||||
|
|
||||||
|
const result = CommandKeys.safeParse(command);
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
logger.info(`Command ${command} recognized.`);
|
||||||
|
handleCommand(result.data, parameters, message.channel.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resolveModContext(message: Message) {
|
||||||
|
const guild = message.guild;
|
||||||
|
if (!guild) {
|
||||||
|
logger.error(`Guild not found for message ${message.id}.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const roleMod = guild.roles.cache.get(config.roleMapping.mod);
|
||||||
|
|
||||||
|
if (!roleMod) {
|
||||||
|
logger.error(`Role ${roleMod} not found in guild ${guild.name}.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const member = await guild.members.fetch(message.author.id);
|
||||||
|
if (!member) {
|
||||||
|
logger.error(
|
||||||
|
`User with ID ${message.author.id} not found in guild ${guild.name}.`,
|
||||||
|
);
|
||||||
|
throw new Error("User not found");
|
||||||
|
}
|
||||||
|
if (!member.roles.cache.has(roleMod.id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new Error("Function not implemented.");
|
||||||
|
}
|
||||||
|
function handleCommand(data: string, parameters: string[], id: string) {
|
||||||
|
throw new Error("Function not implemented.");
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import { createLogger } from "@avocadi/bot-core/lib/logger";
|
||||||
|
import { config } from "config";
|
||||||
|
import { RolesService } from "entities/roles/roles.service";
|
||||||
|
import { acceptUserService } from "features/accept-user/accept-user.service";
|
||||||
|
import { logChannelService } from "features/log-channel/log-channel.service";
|
||||||
|
import client from "lib/client";
|
||||||
|
|
||||||
|
const logger = createLogger("ReactionsListener");
|
||||||
|
|
||||||
|
client.on("messageReactionAdd", async (reaction, user) => {
|
||||||
|
const guild = reaction.message.guild;
|
||||||
|
if (!guild) {
|
||||||
|
logger.error(`Guild not found for message ${reaction.message.id}.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.info(`Guild found for message ${reaction.message.id}.`);
|
||||||
|
|
||||||
|
const channelIntroduction = await client.channels.fetch(
|
||||||
|
config.channelMapping.text.introduction,
|
||||||
|
);
|
||||||
|
|
||||||
|
const message = await reaction.message.fetch();
|
||||||
|
|
||||||
|
// check if valid channel
|
||||||
|
if (message.guild?.id && message.channel?.id === channelIntroduction?.id) {
|
||||||
|
logger.info("valid channel");
|
||||||
|
|
||||||
|
const member = guild?.members.cache.get(user.id);
|
||||||
|
|
||||||
|
// check if member who reacted has role MOD
|
||||||
|
if (member?.roles.cache.get(config.roleMapping.mod)) {
|
||||||
|
const messageAuthor_User = await message.author.fetch();
|
||||||
|
|
||||||
|
if (messageAuthor_User) {
|
||||||
|
const roleMemberId = config.roleMapping.people;
|
||||||
|
|
||||||
|
const messageAuthor_GuildMember = await guild?.members.fetch(
|
||||||
|
messageAuthor_User.id,
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
!messageAuthor_GuildMember?.roles.cache.find(
|
||||||
|
(r) => r.id === roleMemberId,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
logger.info(`accepting ${messageAuthor_User?.username}...`);
|
||||||
|
|
||||||
|
const rolesService = new RolesService();
|
||||||
|
rolesService.assignRole(messageAuthor_GuildMember, roleMemberId);
|
||||||
|
|
||||||
|
await acceptUserService.sendDmAcceptUser(messageAuthor_User);
|
||||||
|
await logChannelService.sendLogMessage(
|
||||||
|
`introduction of <@${messageAuthor_User.id}> got accepted`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
13
adapters/discord/src/listeners/ready.listener.ts
Normal file
13
adapters/discord/src/listeners/ready.listener.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { activityService } from "features/activity/activity.service";
|
||||||
|
import { logChannelService } from "features/log-channel/log-channel.service";
|
||||||
|
import client from "lib/client";
|
||||||
|
import { logger } from "lib/common-logger";
|
||||||
|
|
||||||
|
client.once("clientReady", async () => {
|
||||||
|
await logChannelService.sendLogMessage("wieder online!!!");
|
||||||
|
|
||||||
|
logger.info("bot is online");
|
||||||
|
|
||||||
|
await activityService.set("competing");
|
||||||
|
logger.info("finished ready procedure");
|
||||||
|
});
|
||||||
15
adapters/discord/src/listeners/stop.listener.ts
Normal file
15
adapters/discord/src/listeners/stop.listener.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { handleShutdown } from "actions/shutdown";
|
||||||
|
|
||||||
|
process.on("exit", async () => {
|
||||||
|
await handleShutdown();
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("SIGINT", async () => {
|
||||||
|
await handleShutdown();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("SIGTERM", async () => {
|
||||||
|
await handleShutdown();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import type { VoiceState } from "discord.js";
|
||||||
|
import { dynamicVoiceChannelService } from "features/dynamic-voice-channel/dynamic-voice-channel.service";
|
||||||
|
import { logger } from "lib/common-logger";
|
||||||
|
|
||||||
|
export const handleDynamicVoiceChannelCreation = async (
|
||||||
|
oldState: VoiceState,
|
||||||
|
newState: VoiceState,
|
||||||
|
) => {
|
||||||
|
const userJoinedChannel = !oldState.channelId && newState.channelId;
|
||||||
|
const userSwitchedChannel = oldState.channelId !== newState.channelId;
|
||||||
|
|
||||||
|
if (userJoinedChannel || userSwitchedChannel) {
|
||||||
|
const channel = newState.channel;
|
||||||
|
|
||||||
|
if (!channel) {
|
||||||
|
logger.error("Channel not found for VoiceStateUpdate event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const member = newState.member;
|
||||||
|
if (!member) {
|
||||||
|
logger.error("Member not found for VoiceStateUpdate event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// New channel is created if user joined one of the specific channels (e.g. "Join to Create") or switched to one of them
|
||||||
|
const newChannel =
|
||||||
|
await dynamicVoiceChannelService.createDynamicVoiceChannel(
|
||||||
|
{ name: member.displayName, id: member.id },
|
||||||
|
channel.id,
|
||||||
|
);
|
||||||
|
logger.debug(`Channel found for VoiceStateUpdate event: ${channel.name}`);
|
||||||
|
if (newChannel) {
|
||||||
|
await newState.setChannel(newChannel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import type { VoiceState } from "discord.js";
|
||||||
|
import { voiceChannelsService } from "entities/channels/voice/voice-channels.service";
|
||||||
|
import { dynamicVoiceChannelService } from "features/dynamic-voice-channel/dynamic-voice-channel.service";
|
||||||
|
|
||||||
|
export const handleDynamicVoiceChannelDeletion = async (
|
||||||
|
oldState: VoiceState,
|
||||||
|
newState: VoiceState,
|
||||||
|
) => {
|
||||||
|
if (!(oldState || newState)) return;
|
||||||
|
|
||||||
|
const userSwitchedChannel = oldState.channelId !== newState.channelId;
|
||||||
|
const userLeftChannel = !oldState.channelId && newState.channelId;
|
||||||
|
|
||||||
|
// Check if user left a channel that was created by the bot and delete it if it's empty
|
||||||
|
if (userSwitchedChannel || userLeftChannel) {
|
||||||
|
const channelId = oldState.channelId;
|
||||||
|
|
||||||
|
if (!channelId) return;
|
||||||
|
|
||||||
|
if (dynamicVoiceChannelService.createdChannelIdsSet.has(channelId)) {
|
||||||
|
const channel = await voiceChannelsService.getVoiceChannelById(channelId);
|
||||||
|
|
||||||
|
if (!channel) return;
|
||||||
|
|
||||||
|
if (channel.members.size === 0) {
|
||||||
|
await dynamicVoiceChannelService.deleteDynamicVoiceChannel(channelId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { Events } from "discord.js";
|
||||||
|
import client from "lib/client";
|
||||||
|
import { handleDynamicVoiceChannelCreation } from "./handle-dynamic-voice-channel-creation";
|
||||||
|
import { handleDynamicVoiceChannelDeletion } from "./handle-dynamic-voice-channel-deletion";
|
||||||
|
|
||||||
|
client.on(Events.VoiceStateUpdate, async (oldState, newState) => {
|
||||||
|
await Promise.allSettled([
|
||||||
|
handleDynamicVoiceChannelCreation(oldState, newState),
|
||||||
|
handleDynamicVoiceChannelDeletion(oldState, newState),
|
||||||
|
]);
|
||||||
|
});
|
||||||
31
adapters/discord/tsconfig.json
Normal file
31
adapters/discord/tsconfig.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
// Environment setup & latest features
|
||||||
|
"lib": ["ESNext"],
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "Preserve",
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"allowJs": true,
|
||||||
|
|
||||||
|
// Bundler mode
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
// Best practices
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
|
||||||
|
"baseUrl": "src",
|
||||||
|
|
||||||
|
// Some stricter flags (disabled by default)
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"noUnusedParameters": false,
|
||||||
|
"noPropertyAccessFromIndexSignature": false
|
||||||
|
}
|
||||||
|
}
|
||||||
9
adapters/discord/tsdown.config.ts
Normal file
9
adapters/discord/tsdown.config.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { defineConfig } from "tsdown";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
entry: ["./src/index.ts"],
|
||||||
|
format: "esm",
|
||||||
|
dts: true,
|
||||||
|
exports: true,
|
||||||
|
fixedExtension: false,
|
||||||
|
});
|
||||||
36
adapters/fluxer/.gitignore
vendored
Normal file
36
adapters/fluxer/.gitignore
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# dependencies (bun install)
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# output
|
||||||
|
out
|
||||||
|
dist
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# code coverage
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# logs
|
||||||
|
logs
|
||||||
|
_.log
|
||||||
|
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.local
|
||||||
|
.env.dev
|
||||||
|
.env.prod
|
||||||
|
|
||||||
|
# caches
|
||||||
|
.eslintcache
|
||||||
|
.cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# IntelliJ based IDEs
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Finder (MacOS) folder config
|
||||||
|
.DS_Store
|
||||||
106
adapters/fluxer/CLAUDE.md
Normal file
106
adapters/fluxer/CLAUDE.md
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
|
||||||
|
Default to using Bun instead of Node.js.
|
||||||
|
|
||||||
|
- Use `bun <file>` instead of `node <file>` or `ts-node <file>`
|
||||||
|
- Use `bun test` instead of `jest` or `vitest`
|
||||||
|
- Use `bun build <file.html|file.ts|file.css>` instead of `webpack` or `esbuild`
|
||||||
|
- Use `bun install` instead of `npm install` or `yarn install` or `pnpm install`
|
||||||
|
- Use `bun run <script>` instead of `npm run <script>` or `yarn run <script>` or `pnpm run <script>`
|
||||||
|
- Use `bunx <package> <command>` instead of `npx <package> <command>`
|
||||||
|
- Bun automatically loads .env, so don't use dotenv.
|
||||||
|
|
||||||
|
## APIs
|
||||||
|
|
||||||
|
- `Bun.serve()` supports WebSockets, HTTPS, and routes. Don't use `express`.
|
||||||
|
- `bun:sqlite` for SQLite. Don't use `better-sqlite3`.
|
||||||
|
- `Bun.redis` for Redis. Don't use `ioredis`.
|
||||||
|
- `Bun.sql` for Postgres. Don't use `pg` or `postgres.js`.
|
||||||
|
- `WebSocket` is built-in. Don't use `ws`.
|
||||||
|
- Prefer `Bun.file` over `node:fs`'s readFile/writeFile
|
||||||
|
- Bun.$`ls` instead of execa.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
Use `bun test` to run tests.
|
||||||
|
|
||||||
|
```ts#index.test.ts
|
||||||
|
import { test, expect } from "bun:test";
|
||||||
|
|
||||||
|
test("hello world", () => {
|
||||||
|
expect(1).toBe(1);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Frontend
|
||||||
|
|
||||||
|
Use HTML imports with `Bun.serve()`. Don't use `vite`. HTML imports fully support React, CSS, Tailwind.
|
||||||
|
|
||||||
|
Server:
|
||||||
|
|
||||||
|
```ts#index.ts
|
||||||
|
import index from "./index.html"
|
||||||
|
|
||||||
|
Bun.serve({
|
||||||
|
routes: {
|
||||||
|
"/": index,
|
||||||
|
"/api/users/:id": {
|
||||||
|
GET: (req) => {
|
||||||
|
return new Response(JSON.stringify({ id: req.params.id }));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// optional websocket support
|
||||||
|
websocket: {
|
||||||
|
open: (ws) => {
|
||||||
|
ws.send("Hello, world!");
|
||||||
|
},
|
||||||
|
message: (ws, message) => {
|
||||||
|
ws.send(message);
|
||||||
|
},
|
||||||
|
close: (ws) => {
|
||||||
|
// handle close
|
||||||
|
}
|
||||||
|
},
|
||||||
|
development: {
|
||||||
|
hmr: true,
|
||||||
|
console: true,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
HTML files can import .tsx, .jsx or .js files directly and Bun's bundler will transpile & bundle automatically. `<link>` tags can point to stylesheets and Bun's CSS bundler will bundle.
|
||||||
|
|
||||||
|
```html#index.html
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<h1>Hello, world!</h1>
|
||||||
|
<script type="module" src="./frontend.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
With the following `frontend.tsx`:
|
||||||
|
|
||||||
|
```tsx#frontend.tsx
|
||||||
|
import React from "react";
|
||||||
|
import { createRoot } from "react-dom/client";
|
||||||
|
|
||||||
|
// import .css files directly and it works
|
||||||
|
import './index.css';
|
||||||
|
|
||||||
|
const root = createRoot(document.body);
|
||||||
|
|
||||||
|
export default function Frontend() {
|
||||||
|
return <h1>Hello, world!</h1>;
|
||||||
|
}
|
||||||
|
|
||||||
|
root.render(<Frontend />);
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, run index.ts
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bun --hot ./index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information, read the Bun API docs in `node_modules/bun-types/docs/**.mdx`.
|
||||||
15
adapters/fluxer/README.md
Normal file
15
adapters/fluxer/README.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# fluxer
|
||||||
|
|
||||||
|
To install dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
To run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
This project was created using `bun init` in bun v1.3.5. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
|
||||||
30
adapters/fluxer/package.json
Normal file
30
adapters/fluxer/package.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "@avocadi/bot-adapter-fluxer",
|
||||||
|
"type": "module",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsdown",
|
||||||
|
"dev:prod": "tsdown --watch & NODE_ENV=production node --watch ./dist/index.js",
|
||||||
|
"dev": "tsdown --watch & NODE_ENV=development node --watch ./dist/index.js"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"tsdown": "catalog:"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@avocadi/bot-core": "workspace:*",
|
||||||
|
"@discordjs/rest": "^2.6.0",
|
||||||
|
"@fluxerjs/core": "^1.2.3",
|
||||||
|
"cron": "^4.4.0",
|
||||||
|
"dotenv": "^17.3.1",
|
||||||
|
"dotenv-expand": "^12.0.3",
|
||||||
|
"zod": "catalog:"
|
||||||
|
},
|
||||||
|
"exports": {
|
||||||
|
".": "./dist/index.js",
|
||||||
|
"./package.json": "./package.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
7
adapters/fluxer/src/actions/shutdown.ts
Normal file
7
adapters/fluxer/src/actions/shutdown.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { logChannelService } from "features/log-channel/log-channel.service";
|
||||||
|
import { logger } from "lib/common-logger";
|
||||||
|
|
||||||
|
export const handleShutdown = async () => {
|
||||||
|
logger.info("bot is shutting down...");
|
||||||
|
await logChannelService.sendLogMessage("**S H U T T I N G D O W N**");
|
||||||
|
};
|
||||||
21
adapters/fluxer/src/config/config.schema.ts
Normal file
21
adapters/fluxer/src/config/config.schema.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import {
|
||||||
|
TextChannels,
|
||||||
|
VoiceChannels,
|
||||||
|
} from "@avocadi/bot-core/entities/channels/channels.schema";
|
||||||
|
import { Roles } from "@avocadi/bot-core/entities/roles/roles.schema";
|
||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export const ConfigSchema = z.object({
|
||||||
|
channelMapping: z.object({
|
||||||
|
text: z.record(TextChannels, z.string()),
|
||||||
|
voice: z.record(VoiceChannels, z.string()),
|
||||||
|
}),
|
||||||
|
roleMapping: z.record(Roles, z.string()),
|
||||||
|
serverId: z.string(),
|
||||||
|
version: z.number(),
|
||||||
|
commandPrefix: z.string().default("!"),
|
||||||
|
fluxer: z.object({
|
||||||
|
token: z.string(),
|
||||||
|
applicationId: z.string(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
6
adapters/fluxer/src/config/env/env.schema.ts
vendored
Normal file
6
adapters/fluxer/src/config/env/env.schema.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export const EnvSchema = z.object({
|
||||||
|
FLUXER_APPLICATION_ID: z.string(),
|
||||||
|
FLUXER_TOKEN: z.string(),
|
||||||
|
});
|
||||||
32
adapters/fluxer/src/config/env/index.ts
vendored
Normal file
32
adapters/fluxer/src/config/env/index.ts
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import { join } from "node:path";
|
||||||
|
import dotenv from "dotenv";
|
||||||
|
import dotenvExpand from "dotenv-expand";
|
||||||
|
import { EnvSchema } from "./env.schema";
|
||||||
|
import { logger } from "lib/common-logger";
|
||||||
|
|
||||||
|
const envFile =
|
||||||
|
process.env.NODE_ENV === "production" ? ".env.prod" : ".env.dev";
|
||||||
|
|
||||||
|
const envPath = join(process.cwd(), envFile);
|
||||||
|
|
||||||
|
const rawEnv = Buffer.from(
|
||||||
|
readFileSync(envPath, {
|
||||||
|
encoding: "utf8",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const envJson = { processEnv: dotenv.parse(rawEnv) };
|
||||||
|
|
||||||
|
const targetObj = {};
|
||||||
|
|
||||||
|
const expandedEnv = dotenvExpand.expand({
|
||||||
|
processEnv: targetObj,
|
||||||
|
parsed: envJson.processEnv,
|
||||||
|
}) as { processEnv: Record<string, string> };
|
||||||
|
|
||||||
|
const env = EnvSchema.parse(expandedEnv.processEnv);
|
||||||
|
|
||||||
|
export default env;
|
||||||
|
|
||||||
|
logger.debug(`dev mode: ${process.env.NODE_ENV}`);
|
||||||
46
adapters/fluxer/src/config/index.ts
Normal file
46
adapters/fluxer/src/config/index.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import type z from "zod";
|
||||||
|
import { ConfigSchema } from "./config.schema";
|
||||||
|
import env from "./env";
|
||||||
|
|
||||||
|
const configInput: z.input<typeof ConfigSchema> = {
|
||||||
|
channelMapping: {
|
||||||
|
text: {
|
||||||
|
bot: "1473270893617315899",
|
||||||
|
bump: "",
|
||||||
|
feedback: "1475069278198489089",
|
||||||
|
help: "",
|
||||||
|
introduction: "1473060169972367394",
|
||||||
|
news: "1474477662908567694",
|
||||||
|
log: "1473380467480031548",
|
||||||
|
general: "1473029758951358491",
|
||||||
|
rules: "1473070476174811195",
|
||||||
|
testing: "1479976182517571597",
|
||||||
|
welcome: "1473270114214928440",
|
||||||
|
pomodoro: "",
|
||||||
|
},
|
||||||
|
voice: {
|
||||||
|
custom: "1473379743132119291",
|
||||||
|
"for-four": "",
|
||||||
|
"for-group": "",
|
||||||
|
"for-three": "",
|
||||||
|
"for-two": "",
|
||||||
|
"pomodoro-25-5": "",
|
||||||
|
"pomodoro-50-10": "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
roleMapping: {
|
||||||
|
admin: "1473247543363493913",
|
||||||
|
mention: "",
|
||||||
|
mod: "1473030728028581901",
|
||||||
|
people: "1473269130013061131",
|
||||||
|
bot: "1473321354377535512",
|
||||||
|
},
|
||||||
|
serverId: "1473029758951358488",
|
||||||
|
version: 1,
|
||||||
|
fluxer: {
|
||||||
|
token: env.FLUXER_TOKEN,
|
||||||
|
applicationId: env.FLUXER_APPLICATION_ID,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const config = ConfigSchema.parse(configInput);
|
||||||
56
adapters/fluxer/src/entities/messages/messages.service.ts
Normal file
56
adapters/fluxer/src/entities/messages/messages.service.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import type { MessagesServiceInterface } from "@avocadi/bot-core/entities/messages/messages.service";
|
||||||
|
import { createLogger } from "@avocadi/bot-core/lib/logger";
|
||||||
|
import type {
|
||||||
|
Channel,
|
||||||
|
Message,
|
||||||
|
MessageSendOptions,
|
||||||
|
User,
|
||||||
|
} from "@fluxerjs/core";
|
||||||
|
|
||||||
|
import { logChannelService } from "features/log-channel/log-channel.service";
|
||||||
|
import client from "lib/client";
|
||||||
|
|
||||||
|
export class MessagesService
|
||||||
|
implements
|
||||||
|
MessagesServiceInterface<User, Message, Channel, MessageSendOptions>
|
||||||
|
{
|
||||||
|
private logger = createLogger("MessagesService");
|
||||||
|
|
||||||
|
async sendToUser(
|
||||||
|
userInput: User,
|
||||||
|
createMessageInput: MessageSendOptions,
|
||||||
|
): Promise<void> {
|
||||||
|
const user = await client.users.fetch(userInput.id);
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
await user.send(createMessageInput);
|
||||||
|
} else {
|
||||||
|
this.logger.error(`User with ID ${userInput.id} not found.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendToChannel(
|
||||||
|
channel: Channel,
|
||||||
|
createMessageInput: MessageSendOptions,
|
||||||
|
): Promise<void> {
|
||||||
|
const fetchedChannel = await client.channels.fetch(channel.id);
|
||||||
|
|
||||||
|
if (fetchedChannel?.isSendable()) {
|
||||||
|
await fetchedChannel.send(createMessageInput);
|
||||||
|
} else {
|
||||||
|
this.logger.error(
|
||||||
|
`Channel with ID ${channel.id} not found or is not text-based.`,
|
||||||
|
);
|
||||||
|
|
||||||
|
throw new Error("Channel not found or is not text-based.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async logMessage(message: Message): Promise<void> {
|
||||||
|
const logMessage = `<@${message.author.id}> sent a message:\n"${message.content}"`;
|
||||||
|
|
||||||
|
await logChannelService.sendLogMessage(logMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const messagesService = new MessagesService();
|
||||||
39
adapters/fluxer/src/entities/roles/roles.service.ts
Normal file
39
adapters/fluxer/src/entities/roles/roles.service.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import type { RolesServiceInterface } from "@avocadi/bot-core/entities/roles/roles.service";
|
||||||
|
import { createLogger } from "@avocadi/bot-core/lib/logger";
|
||||||
|
import type { GuildMember } from "@fluxerjs/core";
|
||||||
|
|
||||||
|
export class RolesService implements RolesServiceInterface<GuildMember> {
|
||||||
|
private logger = createLogger("RolesService");
|
||||||
|
|
||||||
|
async assignRole(user: GuildMember, roleId: string) {
|
||||||
|
const roleToAssign = user.guild.roles.has(roleId);
|
||||||
|
if (!roleToAssign) {
|
||||||
|
this.logger.error(
|
||||||
|
`Role ${roleId} not found in guild ${user.guild.name}.`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.logger.info(`Role ${roleId} found in guild ${user.guild.name}.`);
|
||||||
|
await user.guild.addRoleToMember(user.id, roleId);
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeRole(user: GuildMember, role: string) {
|
||||||
|
const roleToRemove = user.guild.roles.has(role);
|
||||||
|
if (!roleToRemove) {
|
||||||
|
this.logger.error(`Role ${role} not found in guild ${user.guild.name}.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await user.guild.removeRoleFromMember(user.id, role);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** get all roles of GuildMember */
|
||||||
|
async getRoles(user: GuildMember) {
|
||||||
|
return user.roles.map((role) => role);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** check if GuildMember has a specific role */
|
||||||
|
async hasRole(user: GuildMember, role: string) {
|
||||||
|
return user.roles.includes(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { AcceptUserService } from "@avocadi/bot-core/features/accept-user/accept-user.service";
|
||||||
|
import { i18nService } from "@avocadi/bot-core/lib/i18n";
|
||||||
|
import type { User } from "@fluxerjs/core";
|
||||||
|
import { messagesService } from "entities/messages/messages.service";
|
||||||
|
|
||||||
|
export const acceptUserService = new AcceptUserService<User>(
|
||||||
|
messagesService,
|
||||||
|
i18nService,
|
||||||
|
"en",
|
||||||
|
);
|
||||||
19
adapters/fluxer/src/features/activity/activity.schema.ts
Normal file
19
adapters/fluxer/src/features/activity/activity.schema.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
export const Activities = z.enum([
|
||||||
|
"playing",
|
||||||
|
"streaming",
|
||||||
|
"listening",
|
||||||
|
"watching",
|
||||||
|
"competing",
|
||||||
|
"invisible",
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const ActivityLocales: Record<z.infer<typeof Activities>, string> = {
|
||||||
|
playing: "spielt sudoku",
|
||||||
|
streaming: "streamt sudoku",
|
||||||
|
listening: "hört sudoku",
|
||||||
|
watching: "schaut sudoku",
|
||||||
|
competing: "wettstreitet sudoku",
|
||||||
|
invisible: "versteckt sudoku",
|
||||||
|
};
|
||||||
35
adapters/fluxer/src/features/activity/activity.service.ts
Normal file
35
adapters/fluxer/src/features/activity/activity.service.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import client from "lib/client";
|
||||||
|
import type z from "zod";
|
||||||
|
import { type Activities, ActivityLocales } from "./activity.schema";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the activity of the bot. This can be used to show that the bot is playing a game, listening to music, etc.
|
||||||
|
*/
|
||||||
|
export class ActivityService {
|
||||||
|
async set(activity: z.output<typeof Activities>) {
|
||||||
|
if (activity === "invisible") {
|
||||||
|
client.options.presence = {
|
||||||
|
status: "invisible",
|
||||||
|
activities: [],
|
||||||
|
afk: false,
|
||||||
|
...client.options.presence,
|
||||||
|
};
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.options.presence = {
|
||||||
|
status: "online",
|
||||||
|
activities: [
|
||||||
|
{
|
||||||
|
name: ActivityLocales[activity],
|
||||||
|
type: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
afk: false,
|
||||||
|
...client.options.presence,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const activityService = new ActivityService();
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { GreetingService } from "@avocadi/bot-core/features/greeting/greeting.service";
|
||||||
|
import { i18nService } from "@avocadi/bot-core/lib/i18n";
|
||||||
|
import { messagesService } from "entities/messages/messages.service";
|
||||||
|
|
||||||
|
export const greetingService = new GreetingService(
|
||||||
|
messagesService,
|
||||||
|
i18nService,
|
||||||
|
"en",
|
||||||
|
);
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { createLogger } from "@avocadi/bot-core/lib/logger";
|
||||||
|
import { config } from "config";
|
||||||
|
import client from "lib/client";
|
||||||
|
|
||||||
|
export class LogChannelService {
|
||||||
|
private logger = createLogger("LogChannelService");
|
||||||
|
|
||||||
|
private logChannelId =
|
||||||
|
process.env.NODE_ENV === "production"
|
||||||
|
? config.channelMapping.text.log
|
||||||
|
: config.channelMapping.text.testing;
|
||||||
|
|
||||||
|
async getLogChannel() {
|
||||||
|
this.logger.debug(`fetching log channel with ID: ${this.logChannelId}`);
|
||||||
|
|
||||||
|
const logChannel = await client.channels.fetch(this.logChannelId);
|
||||||
|
|
||||||
|
if (logChannel.isSendable()) {
|
||||||
|
return logChannel;
|
||||||
|
} else {
|
||||||
|
this.logger.fatal("log channel not found or is not text-based.");
|
||||||
|
throw new Error("log channel not found or is not text-based");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendLogMessage(message: string) {
|
||||||
|
const logChannel = await this.getLogChannel();
|
||||||
|
|
||||||
|
await logChannel.send(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const logChannelService = new LogChannelService();
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { WaterMeService } from "@avocadi/bot-core/features/water-me/water-me.service";
|
||||||
|
import { i18nService } from "@avocadi/bot-core/lib/i18n";
|
||||||
|
import { messagesService } from "entities/messages/messages.service";
|
||||||
|
|
||||||
|
export const waterMeService = new WaterMeService(
|
||||||
|
messagesService,
|
||||||
|
i18nService,
|
||||||
|
"en",
|
||||||
|
);
|
||||||
1
adapters/fluxer/src/index.ts
Normal file
1
adapters/fluxer/src/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import "listeners";
|
||||||
11
adapters/fluxer/src/lib/client.ts
Normal file
11
adapters/fluxer/src/lib/client.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { Client } from "@fluxerjs/core";
|
||||||
|
import { config } from "config";
|
||||||
|
import { logger } from "./common-logger";
|
||||||
|
|
||||||
|
const client = new Client({ intents: 0 });
|
||||||
|
|
||||||
|
await client.login(config.fluxer.token);
|
||||||
|
|
||||||
|
logger.info("fluxer client logged in successfully.");
|
||||||
|
|
||||||
|
export default client;
|
||||||
3
adapters/fluxer/src/lib/common-logger.ts
Normal file
3
adapters/fluxer/src/lib/common-logger.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { createLogger } from "@avocadi/bot-core/lib/logger";
|
||||||
|
|
||||||
|
export const logger = createLogger("FluxerAdapter");
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { Events, type GuildMember } from "@fluxerjs/core";
|
||||||
|
import { config } from "config";
|
||||||
|
import { greetingService } from "features/greeting/greeting.service";
|
||||||
|
import { logChannelService } from "features/log-channel/log-channel.service";
|
||||||
|
import client from "lib/client";
|
||||||
|
import { logger } from "lib/common-logger";
|
||||||
|
|
||||||
|
client.on(Events.GuildMemberAdd, async (member: GuildMember) => {
|
||||||
|
logger.info(`${member.user.username} joined the server}`);
|
||||||
|
if (member.user.bot) return;
|
||||||
|
|
||||||
|
const channel = await client.channels.fetch(
|
||||||
|
process.env.NODE_ENV === "production"
|
||||||
|
? config.channelMapping.text.welcome
|
||||||
|
: config.channelMapping.text.testing,
|
||||||
|
);
|
||||||
|
|
||||||
|
await logChannelService.sendLogMessage(
|
||||||
|
`new member: <@${member.user.id}> (${member.user.username}) joined the server.`,
|
||||||
|
);
|
||||||
|
await greetingService.sendGreeting(member.user.id, channel);
|
||||||
|
await greetingService.sendDmGreeting(member.user);
|
||||||
|
});
|
||||||
6
adapters/fluxer/src/listeners/index.ts
Normal file
6
adapters/fluxer/src/listeners/index.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import "./ready.listener";
|
||||||
|
import "./stop.listener";
|
||||||
|
import "./messages/messages.listener";
|
||||||
|
import "./reactions/reactions.listener";
|
||||||
|
import "./guild-members/guild-members.listener";
|
||||||
|
import "./voice-state/voice-state.listener";
|
||||||
23
adapters/fluxer/src/listeners/messages/handle-command.ts
Normal file
23
adapters/fluxer/src/listeners/messages/handle-command.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { CommandKeys } from "@avocadi/bot-core/entities/commands/commands.schema";
|
||||||
|
import { waterMeService } from "features/water-me/water-me.service";
|
||||||
|
import type z from "zod";
|
||||||
|
|
||||||
|
export const handleCommand = async (
|
||||||
|
command: z.output<typeof CommandKeys>,
|
||||||
|
parameters: Array<string>,
|
||||||
|
channelId: string,
|
||||||
|
) => {
|
||||||
|
switch (command) {
|
||||||
|
case CommandKeys.enum["water-avocadi"]: {
|
||||||
|
// handle giessen command
|
||||||
|
|
||||||
|
waterMeService.handleCommand(channelId);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
// handle unknown command
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
71
adapters/fluxer/src/listeners/messages/messages.listener.ts
Normal file
71
adapters/fluxer/src/listeners/messages/messages.listener.ts
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import { CommandKeys } from "@avocadi/bot-core/entities/commands/commands.schema";
|
||||||
|
import { type Channel, Events, type Message } from "@fluxerjs/core";
|
||||||
|
import { config } from "config";
|
||||||
|
import { messagesService } from "entities/messages/messages.service";
|
||||||
|
import client from "lib/client";
|
||||||
|
import { logger } from "lib/common-logger";
|
||||||
|
import { handleCommand } from "./handle-command";
|
||||||
|
|
||||||
|
// https://fluxerjs.blstmo.com/v/latest/docs/classes/DMChannel
|
||||||
|
|
||||||
|
client.on(Events.MessageCreate, async (message: Message) => {
|
||||||
|
const channel =
|
||||||
|
client.channels.get(message.channelId) ??
|
||||||
|
(await client.channels.fetch(message.channelId));
|
||||||
|
if (channel?.isDM()) {
|
||||||
|
await messagesService.logMessage(message);
|
||||||
|
//await forward(message /*, channel as DMChannel*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.content?.startsWith(config.commandPrefix) && channel) {
|
||||||
|
await recognizedCommand(message, channel);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//async function forward(message: Message /*, channel: DMChannel*/) {
|
||||||
|
// const author = message.author;
|
||||||
|
// console.log(`forward message from ${author.username}`);
|
||||||
|
// let context: string;
|
||||||
|
|
||||||
|
// getting the recipient is currently not supported in fluxer.js
|
||||||
|
/*if (message.author.bot) {
|
||||||
|
const channelId = channel.id;
|
||||||
|
const recipient = channel.recipients[0]?.id;
|
||||||
|
context = `<@${author}> hat an <@${recipient}> geschrieben:\n"${message.content}"`;
|
||||||
|
} else {*/
|
||||||
|
//context = `<@${author.id}> wrote:\n"${message.content}"`;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//await logChannelService.sendLogMessage(context);
|
||||||
|
// `<@${messageAuthor?.id}> wrote to <@${client.user?.id}>\n"${message.content}"`,
|
||||||
|
//}
|
||||||
|
|
||||||
|
async function recognizedCommand(message: Message, channel: Channel) {
|
||||||
|
if (!channel) return;
|
||||||
|
await messagesService.logMessage(message);
|
||||||
|
logger.info(
|
||||||
|
`Command received: ${message.content} from user ${message.author.id}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const commandWithoutPrefix = message.content
|
||||||
|
.slice(config.commandPrefix.length)
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
const commandParts = commandWithoutPrefix.split(" ");
|
||||||
|
|
||||||
|
if (commandParts.length === 0) {
|
||||||
|
logger.warn("No command found after prefix.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [command, ...parameters] = commandParts;
|
||||||
|
|
||||||
|
logger.info(`Parsed command: ${command}`);
|
||||||
|
|
||||||
|
const result = CommandKeys.safeParse(command);
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
logger.info(`Command ${command} recognized.`);
|
||||||
|
await handleCommand(result.data, parameters, channel.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { Events, type MessageReaction, type User } from "@fluxerjs/core";
|
||||||
|
import { config } from "config";
|
||||||
|
import { RolesService } from "entities/roles/roles.service";
|
||||||
|
import { acceptUserService } from "features/accept-user/accept-user.service";
|
||||||
|
import { logChannelService } from "features/log-channel/log-channel.service";
|
||||||
|
import client from "lib/client";
|
||||||
|
|
||||||
|
//const logger = createLogger("ReactionsListener");
|
||||||
|
|
||||||
|
client.on(
|
||||||
|
Events.MessageReactionAdd,
|
||||||
|
async (
|
||||||
|
reaction: MessageReaction,
|
||||||
|
_user: User,
|
||||||
|
_messageId: string,
|
||||||
|
channelId: string,
|
||||||
|
_emoji: string,
|
||||||
|
userId: string,
|
||||||
|
) => {
|
||||||
|
const message = await reaction.fetchMessage();
|
||||||
|
|
||||||
|
if (!message || !reaction.guildId) return;
|
||||||
|
|
||||||
|
const guild = client.guilds.get(reaction.guildId);
|
||||||
|
if (!guild) return;
|
||||||
|
|
||||||
|
const channelIntroduction = await client.channels.fetch(
|
||||||
|
config.channelMapping.text.introduction,
|
||||||
|
);
|
||||||
|
if (guild.id && channelId === channelIntroduction?.id) {
|
||||||
|
const reactionUser =
|
||||||
|
guild.members.get(userId) ?? (await guild.fetchMember(userId));
|
||||||
|
|
||||||
|
if (reactionUser?.roles.find((r) => r === config.roleMapping.mod)) {
|
||||||
|
const messageUser = message.author;
|
||||||
|
|
||||||
|
if (!messageUser) return;
|
||||||
|
|
||||||
|
const roleMemberId = config.roleMapping.people;
|
||||||
|
|
||||||
|
const messageAuthor_GuildMember =
|
||||||
|
guild.members.get(messageUser.id) ??
|
||||||
|
(await guild.fetchMember(messageUser.id));
|
||||||
|
|
||||||
|
if (!messageAuthor_GuildMember.roles.find((r) => r === roleMemberId)) {
|
||||||
|
const rolesService = new RolesService();
|
||||||
|
await rolesService.assignRole(
|
||||||
|
messageAuthor_GuildMember,
|
||||||
|
roleMemberId,
|
||||||
|
);
|
||||||
|
|
||||||
|
await acceptUserService.sendDmAcceptUser(messageUser);
|
||||||
|
await logChannelService.sendLogMessage(
|
||||||
|
`introduction of <@${messageUser.id}> got accepted`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
14
adapters/fluxer/src/listeners/ready.listener.ts
Normal file
14
adapters/fluxer/src/listeners/ready.listener.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { Events } from "@fluxerjs/core";
|
||||||
|
import { activityService } from "features/activity/activity.service";
|
||||||
|
import { logChannelService } from "features/log-channel/log-channel.service";
|
||||||
|
import client from "lib/client";
|
||||||
|
import { logger } from "lib/common-logger";
|
||||||
|
|
||||||
|
client.on(Events.Ready, async () => {
|
||||||
|
await logChannelService.sendLogMessage("**O N L I N E**");
|
||||||
|
|
||||||
|
logger.info("bot is online");
|
||||||
|
|
||||||
|
await activityService.set("competing");
|
||||||
|
logger.info("finished ready procedure");
|
||||||
|
});
|
||||||
15
adapters/fluxer/src/listeners/stop.listener.ts
Normal file
15
adapters/fluxer/src/listeners/stop.listener.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { handleShutdown } from "actions/shutdown";
|
||||||
|
|
||||||
|
process.on("exit", async () => {
|
||||||
|
await handleShutdown();
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("SIGINT", async () => {
|
||||||
|
await handleShutdown();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("SIGTERM", async () => {
|
||||||
|
await handleShutdown();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import { Events, type GuildMember, User } from "@fluxerjs/core";
|
||||||
|
import client from "lib/client";
|
||||||
|
import { logger } from "lib/common-logger";
|
||||||
|
|
||||||
|
interface VoiceStateUpdate {
|
||||||
|
guild_id?: string;
|
||||||
|
channel_id: string | null;
|
||||||
|
user_id: string;
|
||||||
|
connection_id: string;
|
||||||
|
session_id?: string;
|
||||||
|
deaf: boolean;
|
||||||
|
mute: boolean;
|
||||||
|
self_deaf: boolean;
|
||||||
|
self_mute: boolean;
|
||||||
|
self_video: boolean;
|
||||||
|
self_stream: boolean;
|
||||||
|
is_mobile: boolean;
|
||||||
|
viewer_stream_keys?: string[];
|
||||||
|
version: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.on(Events.VoiceStateUpdate, async (data: VoiceStateUpdate) => {
|
||||||
|
// logger.debug(data);
|
||||||
|
// return;
|
||||||
|
const guildId = data.guild_id;
|
||||||
|
if (!guildId) return;
|
||||||
|
|
||||||
|
const guild = await client.guilds.fetch(guildId);
|
||||||
|
if (!guild) return;
|
||||||
|
|
||||||
|
const userId = data.user_id;
|
||||||
|
if (!userId) return;
|
||||||
|
|
||||||
|
const channelId = data.channel_id;
|
||||||
|
if (!channelId) {
|
||||||
|
logger.debug("!channelId");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.debug(`channelId: ${channelId}`);
|
||||||
|
|
||||||
|
const member = guild.members.get(userId) ?? (await guild.fetchMember(userId));
|
||||||
|
if (!channelId) {
|
||||||
|
logger.debug("!channelId");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.debug(`channelId: ${channelId}`);
|
||||||
|
|
||||||
|
const channel =
|
||||||
|
client.channels.get(channelId) ?? (await client.channels.fetch(channelId));
|
||||||
|
if (!channel) {
|
||||||
|
logger.debug("!channel");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.debug(`channel: ${channel}`);
|
||||||
|
|
||||||
|
if (!member?.user) {
|
||||||
|
logger.debug("!member?.user");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.debug(`member?.user${member?.user}`);
|
||||||
|
|
||||||
|
logger.debug("user joined vc");
|
||||||
|
if (!member?.user.bot) {
|
||||||
|
logger.debug("!member.user.bot");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.debug("user joined vc");
|
||||||
|
});
|
||||||
30
adapters/fluxer/tsconfig.json
Normal file
30
adapters/fluxer/tsconfig.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
// Environment setup & latest features
|
||||||
|
"lib": ["ESNext"],
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "Preserve",
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"allowJs": true,
|
||||||
|
|
||||||
|
"baseUrl": "src",
|
||||||
|
// Bundler mode
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
// Best practices
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
|
||||||
|
// Some stricter flags (disabled by default)
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"noUnusedParameters": false,
|
||||||
|
"noPropertyAccessFromIndexSignature": false
|
||||||
|
}
|
||||||
|
}
|
||||||
9
adapters/fluxer/tsdown.config.ts
Normal file
9
adapters/fluxer/tsdown.config.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { defineConfig } from "tsdown";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
entry: ["./src/index.ts"],
|
||||||
|
format: "esm",
|
||||||
|
dts: true,
|
||||||
|
exports: true,
|
||||||
|
fixedExtension: false,
|
||||||
|
});
|
||||||
34
biome.json
Normal file
34
biome.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://biomejs.dev/schemas/2.4.2/schema.json",
|
||||||
|
"vcs": {
|
||||||
|
"enabled": true,
|
||||||
|
"clientKind": "git",
|
||||||
|
"useIgnoreFile": true
|
||||||
|
},
|
||||||
|
"files": {
|
||||||
|
"ignoreUnknown": false
|
||||||
|
},
|
||||||
|
"formatter": {
|
||||||
|
"enabled": true,
|
||||||
|
"indentStyle": "tab"
|
||||||
|
},
|
||||||
|
"linter": {
|
||||||
|
"enabled": true,
|
||||||
|
"rules": {
|
||||||
|
"recommended": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"javascript": {
|
||||||
|
"formatter": {
|
||||||
|
"quoteStyle": "double"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"assist": {
|
||||||
|
"enabled": true,
|
||||||
|
"actions": {
|
||||||
|
"source": {
|
||||||
|
"organizeImports": "on"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
525
bun.lock
Normal file
525
bun.lock
Normal file
@@ -0,0 +1,525 @@
|
|||||||
|
{
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"workspaces": {
|
||||||
|
"": {
|
||||||
|
"name": "avocadi-bot",
|
||||||
|
"dependencies": {
|
||||||
|
"@fluxerjs/core": "^1.1.7",
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@biomejs/biome": "^2.4.2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"adapters/discord": {
|
||||||
|
"name": "@avocadi/bot-adapter-discord",
|
||||||
|
"dependencies": {
|
||||||
|
"@avocadi/bot-core": "workspace:*",
|
||||||
|
"@discordjs/rest": "^2.6.0",
|
||||||
|
"cron": "^4.4.0",
|
||||||
|
"discord.js": "^14.25.1",
|
||||||
|
"dotenv": "^17.3.1",
|
||||||
|
"dotenv-expand": "^12.0.3",
|
||||||
|
"zod": "catalog:",
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"tsdown": "catalog:",
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"adapters/fluxer": {
|
||||||
|
"name": "@avocadi/bot-adapter-fluxer",
|
||||||
|
"dependencies": {
|
||||||
|
"@avocadi/bot-core": "workspace:*",
|
||||||
|
"@discordjs/rest": "^2.6.0",
|
||||||
|
"@fluxerjs/core": "^1.1.7",
|
||||||
|
"cron": "^4.4.0",
|
||||||
|
"dotenv": "^17.3.1",
|
||||||
|
"dotenv-expand": "^12.0.3",
|
||||||
|
"zod": "catalog:",
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"tsdown": "catalog:",
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"core": {
|
||||||
|
"name": "@avocadi/bot-core",
|
||||||
|
"dependencies": {
|
||||||
|
"@discordjs/rest": "^2.4.0",
|
||||||
|
"cron": "^3.3.1",
|
||||||
|
"discord.js": "^14.16.3",
|
||||||
|
"dotenv": "^16.4.7",
|
||||||
|
"drizzle-orm": "^0.38.3",
|
||||||
|
"i18next": "^25.8.11",
|
||||||
|
"tslog": "^4.10.2",
|
||||||
|
"zod": "catalog:",
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "^1.1.14",
|
||||||
|
"better-sqlite3": "^11.7.0",
|
||||||
|
"drizzle-kit": "^0.30.1",
|
||||||
|
"tsdown": "catalog:",
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5.7.2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"trustedDependencies": [
|
||||||
|
"better-sqlite3",
|
||||||
|
"esbuild",
|
||||||
|
],
|
||||||
|
"catalog": {
|
||||||
|
"tsdown": "^0.20.3",
|
||||||
|
"zod": "^4",
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"@avocadi/bot-adapter-discord": ["@avocadi/bot-adapter-discord@workspace:adapters/discord"],
|
||||||
|
|
||||||
|
"@avocadi/bot-adapter-fluxer": ["@avocadi/bot-adapter-fluxer@workspace:adapters/fluxer"],
|
||||||
|
|
||||||
|
"@avocadi/bot-core": ["@avocadi/bot-core@workspace:core"],
|
||||||
|
|
||||||
|
"@babel/generator": ["@babel/generator@8.0.0-rc.1", "", { "dependencies": { "@babel/parser": "^8.0.0-rc.1", "@babel/types": "^8.0.0-rc.1", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "@types/jsesc": "^2.5.0", "jsesc": "^3.0.2" } }, "sha512-3ypWOOiC4AYHKr8vYRVtWtWmyvcoItHtVqF8paFax+ydpmUdPsJpLBkBBs5ItmhdrwC3a0ZSqqFAdzls4ODP3w=="],
|
||||||
|
|
||||||
|
"@babel/helper-string-parser": ["@babel/helper-string-parser@8.0.0-rc.2", "", {}, "sha512-noLx87RwlBEMrTzncWd/FvTxoJ9+ycHNg0n8yyYydIoDsLZuxknKgWRJUqcrVkNrJ74uGyhWQzQaS3q8xfGAhQ=="],
|
||||||
|
|
||||||
|
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@8.0.0-rc.1", "", {}, "sha512-I4YnARytXC2RzkLNVnf5qFNFMzp679qZpmtw/V3Jt2uGnWiIxyJtaukjG7R8pSx8nG2NamICpGfljQsogj+FbQ=="],
|
||||||
|
|
||||||
|
"@babel/parser": ["@babel/parser@8.0.0-rc.1", "", { "dependencies": { "@babel/types": "^8.0.0-rc.1" }, "bin": "./bin/babel-parser.js" }, "sha512-6HyyU5l1yK/7h9Ki52i5h6mDAx4qJdiLQO4FdCyJNoB/gy3T3GGJdhQzzbZgvgZCugYBvwtQiWRt94QKedHnkA=="],
|
||||||
|
|
||||||
|
"@babel/runtime": ["@babel/runtime@7.28.6", "", {}, "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA=="],
|
||||||
|
|
||||||
|
"@babel/types": ["@babel/types@8.0.0-rc.1", "", { "dependencies": { "@babel/helper-string-parser": "^8.0.0-rc.1", "@babel/helper-validator-identifier": "^8.0.0-rc.1" } }, "sha512-ubmJ6TShyaD69VE9DQrlXcdkvJbmwWPB8qYj0H2kaJi29O7vJT9ajSdBd2W8CG34pwL9pYA74fi7RHC1qbLoVQ=="],
|
||||||
|
|
||||||
|
"@biomejs/biome": ["@biomejs/biome@2.4.2", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.2", "@biomejs/cli-darwin-x64": "2.4.2", "@biomejs/cli-linux-arm64": "2.4.2", "@biomejs/cli-linux-arm64-musl": "2.4.2", "@biomejs/cli-linux-x64": "2.4.2", "@biomejs/cli-linux-x64-musl": "2.4.2", "@biomejs/cli-win32-arm64": "2.4.2", "@biomejs/cli-win32-x64": "2.4.2" }, "bin": { "biome": "bin/biome" } }, "sha512-vVE/FqLxNLbvYnFDYg3Xfrh1UdFhmPT5i+yPT9GE2nTUgI4rkqo5krw5wK19YHBd7aE7J6r91RRmb8RWwkjy6w=="],
|
||||||
|
|
||||||
|
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-3pEcKCP/1POKyaZZhXcxFl3+d9njmeAihZ17k8lL/1vk+6e0Cbf0yPzKItFiT+5Yh6TQA4uKvnlqe0oVZwRxCA=="],
|
||||||
|
|
||||||
|
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-P7hK1jLVny+0R9UwyGcECxO6sjETxfPyBm/1dmFjnDOHgdDPjPqozByunrwh4xPKld8sxOr5eAsSqal5uKgeBg=="],
|
||||||
|
|
||||||
|
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-DI3Mi7GT2zYNgUTDEbSjl3e1KhoP76OjQdm8JpvZYZWtVDRyLd3w8llSr2TWk1z+U3P44kUBWY3X7H9MD1/DGQ=="],
|
||||||
|
|
||||||
|
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-/x04YK9+7erw6tYEcJv9WXoBHcULI/wMOvNdAyE9S3JStZZ9yJyV67sWAI+90UHuDo/BDhq0d96LDqGlSVv7WA=="],
|
||||||
|
|
||||||
|
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.2", "", { "os": "linux", "cpu": "x64" }, "sha512-GK2ErnrKpWFigYP68cXiCHK4RTL4IUWhK92AFS3U28X/nuAL5+hTuy6hyobc8JZRSt+upXt1nXChK+tuHHx4mA=="],
|
||||||
|
|
||||||
|
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.2", "", { "os": "linux", "cpu": "x64" }, "sha512-wbBmTkeAoAYbOQ33f6sfKG7pcRSydQiF+dTYOBjJsnXO2mWEOQHllKlC2YVnedqZFERp2WZhFUoO7TNRwnwEHQ=="],
|
||||||
|
|
||||||
|
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-k2uqwLYrNNxnaoiW3RJxoMGnbKda8FuCmtYG3cOtVljs3CzWxaTR+AoXwKGHscC9thax9R4kOrtWqWN0+KdPTw=="],
|
||||||
|
|
||||||
|
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.2", "", { "os": "win32", "cpu": "x64" }, "sha512-9ma7C4g8Sq3cBlRJD2yrsHXB1mnnEBdpy7PhvFrylQWQb4PoyCmPucdX7frvsSBQuFtIiKCrolPl/8tCZrKvgQ=="],
|
||||||
|
|
||||||
|
"@discordjs/builders": ["@discordjs/builders@1.13.1", "", { "dependencies": { "@discordjs/formatters": "^0.6.2", "@discordjs/util": "^1.2.0", "@sapphire/shapeshift": "^4.0.0", "discord-api-types": "^0.38.33", "fast-deep-equal": "^3.1.3", "ts-mixer": "^6.0.4", "tslib": "^2.6.3" } }, "sha512-cOU0UDHc3lp/5nKByDxkmRiNZBpdp0kx55aarbiAfakfKJHlxv/yFW1zmIqCAmwH5CRlrH9iMFKJMpvW4DPB+w=="],
|
||||||
|
|
||||||
|
"@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="],
|
||||||
|
|
||||||
|
"@discordjs/formatters": ["@discordjs/formatters@0.6.2", "", { "dependencies": { "discord-api-types": "^0.38.33" } }, "sha512-y4UPwWhH6vChKRkGdMB4odasUbHOUwy7KL+OVwF86PvT6QVOwElx+TiI1/6kcmcEe+g5YRXJFiXSXUdabqZOvQ=="],
|
||||||
|
|
||||||
|
"@discordjs/rest": ["@discordjs/rest@2.6.0", "", { "dependencies": { "@discordjs/collection": "^2.1.1", "@discordjs/util": "^1.1.1", "@sapphire/async-queue": "^1.5.3", "@sapphire/snowflake": "^3.5.3", "@vladfrangu/async_event_emitter": "^2.4.6", "discord-api-types": "^0.38.16", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", "undici": "6.21.3" } }, "sha512-RDYrhmpB7mTvmCKcpj+pc5k7POKszS4E2O9TYc+U+Y4iaCP+r910QdO43qmpOja8LRr1RJ0b3U+CqVsnPqzf4w=="],
|
||||||
|
|
||||||
|
"@discordjs/util": ["@discordjs/util@1.2.0", "", { "dependencies": { "discord-api-types": "^0.38.33" } }, "sha512-3LKP7F2+atl9vJFhaBjn4nOaSWahZ/yWjOvA4e5pnXkt2qyXRCHLxoBQy81GFtLGCq7K9lPm9R517M1U+/90Qg=="],
|
||||||
|
|
||||||
|
"@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=="],
|
||||||
|
|
||||||
|
"@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="],
|
||||||
|
|
||||||
|
"@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],
|
||||||
|
|
||||||
|
"@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
|
||||||
|
|
||||||
|
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
|
||||||
|
|
||||||
|
"@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=="],
|
||||||
|
|
||||||
|
"@fluxerjs/builders": ["@fluxerjs/builders@1.1.7", "", { "dependencies": { "@fluxerjs/types": "1.1.7", "@fluxerjs/util": "1.1.7" } }, "sha512-EoFfLwW8zFDSKGNuhN7TegMfZC7/3nOa8TIuWW84xK8oPmOkE3WQg4CZhjROIV31zsIimyYwIpCzDKpCfIvjGw=="],
|
||||||
|
|
||||||
|
"@fluxerjs/collection": ["@fluxerjs/collection@1.1.7", "", {}, "sha512-EC0Ndxql3nkTOoe0n7bS7Iil3DgCOc1O56j+f7l2bXPdaqq24oNlYWLxfVw2zQ/qJ9FTvBblyu9nT/KvThD0lQ=="],
|
||||||
|
|
||||||
|
"@fluxerjs/core": ["@fluxerjs/core@1.1.7", "", { "dependencies": { "@fluxerjs/builders": "1.1.7", "@fluxerjs/collection": "1.1.7", "@fluxerjs/rest": "1.1.7", "@fluxerjs/types": "1.1.7", "@fluxerjs/util": "1.1.7", "@fluxerjs/ws": "1.1.7" } }, "sha512-hFVY95F7+b081YHA9R2ecWOy5yz7i/pJVMp/7Oiz2PinVZAwGNKN7adLS6SQYiqO6cISXdXg01EK5cm7r+NJvg=="],
|
||||||
|
|
||||||
|
"@fluxerjs/rest": ["@fluxerjs/rest@1.1.7", "", { "dependencies": { "@fluxerjs/types": "1.1.7" } }, "sha512-UsmUjZWQUuZb+zLRimL2cg/Kborff1Ol/J+mxT6wfWqAVTcslVuyl2y/gHPDDLeKiNhpe09lh9eL58tE5bTDuw=="],
|
||||||
|
|
||||||
|
"@fluxerjs/types": ["@fluxerjs/types@1.1.7", "", {}, "sha512-uEn6ZBbv/SGRLgSHnymZ1DRU5+gG1UncwecxZBJ7B/ZbuhBSRnafIncHSwYs0ZXhlMZtCCpmOGElYPdr9Yc3HQ=="],
|
||||||
|
|
||||||
|
"@fluxerjs/util": ["@fluxerjs/util@1.1.7", "", { "dependencies": { "@fluxerjs/types": "1.1.7" } }, "sha512-Tn4PHetSvI4nYNU/x1/f15BqXmBQbguHq3ESuF+YXUoIo6T3axhGO2Ka+9jngSKHUCqv9/cs00AS6LBCOQfHhw=="],
|
||||||
|
|
||||||
|
"@fluxerjs/ws": ["@fluxerjs/ws@1.1.7", "", { "dependencies": { "@fluxerjs/types": "1.1.7", "ws": "^8.18.0" } }, "sha512-2WGlglxaPZmHQ0FW3OQpHL/ghMV7OI9vm+2FZ7ER0qqR+x3nrxbp7+2EXMtQMz2UpPH2+53/Hexa3+7Ze8dx4A=="],
|
||||||
|
|
||||||
|
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
||||||
|
|
||||||
|
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
||||||
|
|
||||||
|
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
|
||||||
|
|
||||||
|
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
||||||
|
|
||||||
|
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="],
|
||||||
|
|
||||||
|
"@oxc-project/types": ["@oxc-project/types@0.112.0", "", {}, "sha512-m6RebKHIRsax2iCwVpYW2ErQwa4ywHJrE4sCK3/8JK8ZZAWOKXaRJFl/uP51gaVyyXlaS4+chU1nSCdzYf6QqQ=="],
|
||||||
|
|
||||||
|
"@petamoriken/float16": ["@petamoriken/float16@3.9.3", "", {}, "sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g=="],
|
||||||
|
|
||||||
|
"@quansync/fs": ["@quansync/fs@1.0.0", "", { "dependencies": { "quansync": "^1.0.0" } }, "sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.3", "", { "os": "android", "cpu": "arm64" }, "sha512-0T1k9FinuBZ/t7rZ8jN6OpUKPnUjNdYHoj/cESWrQ3ZraAJ4OMm6z7QjSfCxqj8mOp9kTKc1zHK3kGz5vMu+nQ=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-rc.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JWWLzvcmc/3pe7qdJqPpuPk91SoE/N+f3PcWx/6ZwuyDVyungAEJPvKm/eEldiDdwTmaEzWfIR+HORxYWrCi1A=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-rc.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-MTakBxfx3tde5WSmbHxuqlDsIW0EzQym+PJYGF4P6lG2NmKzi128OGynoFUqoD5ryCySEY85dug4v+LWGBElIw=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-rc.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jje3oopyOLs7IwfvXoS6Lxnmie5JJO7vW29fdGFu5YGY1EDbVDhD+P9vDihqS5X6fFiqL3ZQZCMBg6jyHkSVww=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.3", "", { "os": "linux", "cpu": "arm" }, "sha512-A0n8P3hdLAaqzSFrQoA42p23ZKBYQOw+8EH5r15Sa9X1kD9/JXe0YT2gph2QTWvdr0CVK2BOXiK6ENfy6DXOag=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-rc.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-kWXkoxxarYISBJ4bLNf5vFkEbb4JvccOwxWDxuK9yee8lg5XA7OpvlTptfRuwEvYcOZf+7VS69Uenpmpyo5Bjw=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-rc.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-Z03/wrqau9Bicfgb3Dbs6SYTHliELk2PM2LpG2nFd+cGupTMF5kanLEcj2vuuJLLhptNyS61rtk7SOZ+lPsTUA=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-rc.3", "", { "os": "linux", "cpu": "x64" }, "sha512-iSXXZsQp08CSilff/DCTFZHSVEpEwdicV3W8idHyrByrcsRDVh9sGC3sev6d8BygSGj3vt8GvUKBPCoyMA4tgQ=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-rc.3", "", { "os": "linux", "cpu": "x64" }, "sha512-qaj+MFudtdCv9xZo9znFvkgoajLdc+vwf0Kz5N44g+LU5XMe+IsACgn3UG7uTRlCCvhMAGXm1XlpEA5bZBrOcw=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-rc.3", "", { "os": "none", "cpu": "arm64" }, "sha512-U662UnMETyjT65gFmG9ma+XziENrs7BBnENi/27swZPYagubfHRirXHG2oMl+pEax2WvO7Kb9gHZmMakpYqBHQ=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-rc.3", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-gekrQ3Q2HiC1T5njGyuUJoGpK/l6B/TNXKed3fZXNf9YRTJn3L5MOZsFBn4bN2+UX+8+7hgdlTcEsexX988G4g=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-rc.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-85y5JifyMgs8m5K2XzR/VDsapKbiFiohl7s5lEj7nmNGO0pkTXE7q6TQScei96BNAsoK7JC3pA7ukA8WRHVJpg=="],
|
||||||
|
|
||||||
|
"@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-rc.3", "", { "os": "win32", "cpu": "x64" }, "sha512-a4VUQZH7LxGbUJ3qJ/TzQG8HxdHvf+jOnqf7B7oFx1TEBm+j2KNL2zr5SQ7wHkNAcaPevF6gf9tQnVBnC4mD+A=="],
|
||||||
|
|
||||||
|
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.3", "", {}, "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q=="],
|
||||||
|
|
||||||
|
"@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.5", "", {}, "sha512-xzvBr1Q1c4lCe7i6sRnrofxeO1QTP/LKQ6A6qy0iB4x5yfiSfARMEQEghojzTNALDTcv8En04qYNIco9/K9eZQ=="],
|
||||||
|
|
||||||
|
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
|
||||||
|
|
||||||
|
"@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="],
|
||||||
|
|
||||||
|
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
||||||
|
|
||||||
|
"@types/jsesc": ["@types/jsesc@2.5.1", "", {}, "sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw=="],
|
||||||
|
|
||||||
|
"@types/luxon": ["@types/luxon@3.7.1", "", {}, "sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg=="],
|
||||||
|
|
||||||
|
"@types/node": ["@types/node@25.2.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ=="],
|
||||||
|
|
||||||
|
"@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.7", "", {}, "sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g=="],
|
||||||
|
|
||||||
|
"ansis": ["ansis@4.2.0", "", {}, "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig=="],
|
||||||
|
|
||||||
|
"ast-kit": ["ast-kit@3.0.0-beta.1", "", { "dependencies": { "@babel/parser": "^8.0.0-beta.4", "estree-walker": "^3.0.3", "pathe": "^2.0.3" } }, "sha512-trmleAnZ2PxN/loHWVhhx1qeOHSRXq4TDsBBxq3GqeJitfk3+jTQ+v/C1km/KYq9M7wKqCewMh+/NAvVH7m+bw=="],
|
||||||
|
|
||||||
|
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
||||||
|
|
||||||
|
"better-sqlite3": ["better-sqlite3@11.10.0", "", { "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" } }, "sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ=="],
|
||||||
|
|
||||||
|
"bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="],
|
||||||
|
|
||||||
|
"birpc": ["birpc@4.0.0", "", {}, "sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw=="],
|
||||||
|
|
||||||
|
"bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="],
|
||||||
|
|
||||||
|
"buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="],
|
||||||
|
|
||||||
|
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
|
||||||
|
|
||||||
|
"bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="],
|
||||||
|
|
||||||
|
"cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="],
|
||||||
|
|
||||||
|
"chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="],
|
||||||
|
|
||||||
|
"cron": ["cron@4.4.0", "", { "dependencies": { "@types/luxon": "~3.7.0", "luxon": "~3.7.0" } }, "sha512-fkdfq+b+AHI4cKdhZlppHveI/mgz2qpiYxcm+t5E5TsxX7QrLS1VE0+7GENEk9z0EeGPcpSciGv6ez24duWhwQ=="],
|
||||||
|
|
||||||
|
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||||
|
|
||||||
|
"decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="],
|
||||||
|
|
||||||
|
"deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="],
|
||||||
|
|
||||||
|
"defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],
|
||||||
|
|
||||||
|
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
|
||||||
|
|
||||||
|
"discord-api-types": ["discord-api-types@0.38.39", "", {}, "sha512-XRdDQvZvID1XvcFftjSmd4dcmMi/RL/jSy5sduBDAvCGFcNFHThdIQXCEBDZFe52lCNEzuIL0QJoKYAmRmxLUA=="],
|
||||||
|
|
||||||
|
"discord.js": ["discord.js@14.25.1", "", { "dependencies": { "@discordjs/builders": "^1.13.0", "@discordjs/collection": "1.5.3", "@discordjs/formatters": "^0.6.2", "@discordjs/rest": "^2.6.0", "@discordjs/util": "^1.2.0", "@discordjs/ws": "^1.2.3", "@sapphire/snowflake": "3.5.3", "discord-api-types": "^0.38.33", "fast-deep-equal": "3.1.3", "lodash.snakecase": "4.1.1", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", "undici": "6.21.3" } }, "sha512-2l0gsPOLPs5t6GFZfQZKnL1OJNYFcuC/ETWsW4VtKVD/tg4ICa9x+jb9bkPffkMdRpRpuUaO/fKkHCBeiCKh8g=="],
|
||||||
|
|
||||||
|
"dotenv": ["dotenv@17.3.1", "", {}, "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA=="],
|
||||||
|
|
||||||
|
"dotenv-expand": ["dotenv-expand@12.0.3", "", { "dependencies": { "dotenv": "^16.4.5" } }, "sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA=="],
|
||||||
|
|
||||||
|
"drizzle-kit": ["drizzle-kit@0.30.6", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.19.7", "esbuild-register": "^3.5.0", "gel": "^2.0.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-U4wWit0fyZuGuP7iNmRleQyK2V8wCuv57vf5l3MnG4z4fzNTjY/U13M8owyQ5RavqvqxBifWORaR3wIUzlN64g=="],
|
||||||
|
|
||||||
|
"drizzle-orm": ["drizzle-orm@0.38.4", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/react": ">=18", "@types/sql.js": "*", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "react": ">=18", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/react", "@types/sql.js", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "knex", "kysely", "mysql2", "pg", "postgres", "react", "sql.js", "sqlite3"] }, "sha512-s7/5BpLKO+WJRHspvpqTydxFob8i1vo2rEx4pY6TGY7QSMuUfWUuzaY0DIpXCkgHOo37BaFC+SJQb99dDUXT3Q=="],
|
||||||
|
|
||||||
|
"dts-resolver": ["dts-resolver@2.1.3", "", { "peerDependencies": { "oxc-resolver": ">=11.0.0" }, "optionalPeers": ["oxc-resolver"] }, "sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw=="],
|
||||||
|
|
||||||
|
"empathic": ["empathic@2.0.0", "", {}, "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA=="],
|
||||||
|
|
||||||
|
"end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="],
|
||||||
|
|
||||||
|
"env-paths": ["env-paths@3.0.0", "", {}, "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A=="],
|
||||||
|
|
||||||
|
"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=="],
|
||||||
|
|
||||||
|
"esbuild-register": ["esbuild-register@3.6.0", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "esbuild": ">=0.12 <1" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="],
|
||||||
|
|
||||||
|
"estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
|
||||||
|
|
||||||
|
"expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="],
|
||||||
|
|
||||||
|
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||||
|
|
||||||
|
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
|
||||||
|
|
||||||
|
"file-uri-to-path": ["file-uri-to-path@1.0.0", "", {}, "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="],
|
||||||
|
|
||||||
|
"fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="],
|
||||||
|
|
||||||
|
"gel": ["gel@2.2.0", "", { "dependencies": { "@petamoriken/float16": "^3.8.7", "debug": "^4.3.4", "env-paths": "^3.0.0", "semver": "^7.6.2", "shell-quote": "^1.8.1", "which": "^4.0.0" }, "bin": { "gel": "dist/cli.mjs" } }, "sha512-q0ma7z2swmoamHQusey8ayo8+ilVdzDt4WTxSPzq/yRqvucWRfymRVMvNgmSC0XK7eNjjEZEcplxpgaNojKdmQ=="],
|
||||||
|
|
||||||
|
"get-tsconfig": ["get-tsconfig@4.13.6", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw=="],
|
||||||
|
|
||||||
|
"github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="],
|
||||||
|
|
||||||
|
"hookable": ["hookable@6.0.1", "", {}, "sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw=="],
|
||||||
|
|
||||||
|
"i18next": ["i18next@25.8.11", "", { "dependencies": { "@babel/runtime": "^7.28.4" }, "peerDependencies": { "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-LZ32llTLGludnddjLoijHV7TbmVubU5eJnsWf8taiuM3jmSfUuvBLuyDeubJKS1yBjLBgb7As124M4KWNcBvpw=="],
|
||||||
|
|
||||||
|
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
|
||||||
|
|
||||||
|
"import-without-cache": ["import-without-cache@0.2.5", "", {}, "sha512-B6Lc2s6yApwnD2/pMzFh/d5AVjdsDXjgkeJ766FmFuJELIGHNycKRj+l3A39yZPM4CchqNCB4RITEAYB1KUM6A=="],
|
||||||
|
|
||||||
|
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||||
|
|
||||||
|
"ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="],
|
||||||
|
|
||||||
|
"isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="],
|
||||||
|
|
||||||
|
"jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
|
||||||
|
|
||||||
|
"lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="],
|
||||||
|
|
||||||
|
"lodash.snakecase": ["lodash.snakecase@4.1.1", "", {}, "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw=="],
|
||||||
|
|
||||||
|
"luxon": ["luxon@3.7.2", "", {}, "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew=="],
|
||||||
|
|
||||||
|
"magic-bytes.js": ["magic-bytes.js@1.13.0", "", {}, "sha512-afO2mnxW7GDTXMm5/AoN1WuOcdoKhtgXjIvHmobqTD1grNplhGdv3PFOyjCVmrnOZBIT/gD/koDKpYG+0mvHcg=="],
|
||||||
|
|
||||||
|
"mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="],
|
||||||
|
|
||||||
|
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
|
||||||
|
|
||||||
|
"mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="],
|
||||||
|
|
||||||
|
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||||
|
|
||||||
|
"napi-build-utils": ["napi-build-utils@2.0.0", "", {}, "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA=="],
|
||||||
|
|
||||||
|
"node-abi": ["node-abi@3.87.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ=="],
|
||||||
|
|
||||||
|
"obug": ["obug@2.1.1", "", {}, "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ=="],
|
||||||
|
|
||||||
|
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
||||||
|
|
||||||
|
"pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
|
||||||
|
|
||||||
|
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
|
||||||
|
|
||||||
|
"prebuild-install": ["prebuild-install@7.1.3", "", { "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^2.0.0", "node-abi": "^3.3.0", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^4.0.0", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug=="],
|
||||||
|
|
||||||
|
"pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="],
|
||||||
|
|
||||||
|
"quansync": ["quansync@1.0.0", "", {}, "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA=="],
|
||||||
|
|
||||||
|
"rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="],
|
||||||
|
|
||||||
|
"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=="],
|
||||||
|
|
||||||
|
"rolldown": ["rolldown@1.0.0-rc.3", "", { "dependencies": { "@oxc-project/types": "=0.112.0", "@rolldown/pluginutils": "1.0.0-rc.3" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.3", "@rolldown/binding-darwin-arm64": "1.0.0-rc.3", "@rolldown/binding-darwin-x64": "1.0.0-rc.3", "@rolldown/binding-freebsd-x64": "1.0.0-rc.3", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.3", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.3", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.3", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.3", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.3", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.3", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.3", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.3", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.3" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-Po/YZECDOqVXjIXrtC5h++a5NLvKAQNrd9ggrIG3sbDfGO5BqTUsrI6l8zdniKRp3r5Tp/2JTrXqx4GIguFCMw=="],
|
||||||
|
|
||||||
|
"rolldown-plugin-dts": ["rolldown-plugin-dts@0.22.1", "", { "dependencies": { "@babel/generator": "8.0.0-rc.1", "@babel/helper-validator-identifier": "8.0.0-rc.1", "@babel/parser": "8.0.0-rc.1", "@babel/types": "8.0.0-rc.1", "ast-kit": "^3.0.0-beta.1", "birpc": "^4.0.0", "dts-resolver": "^2.1.3", "get-tsconfig": "^4.13.1", "obug": "^2.1.1" }, "peerDependencies": { "@ts-macro/tsc": "^0.3.6", "@typescript/native-preview": ">=7.0.0-dev.20250601.1", "rolldown": "^1.0.0-rc.3", "typescript": "^5.0.0", "vue-tsc": "~3.2.0" }, "optionalPeers": ["@ts-macro/tsc", "@typescript/native-preview", "typescript", "vue-tsc"] }, "sha512-5E0AiM5RSQhU6cjtkDFWH6laW4IrMu0j1Mo8x04Xo1ALHmaRMs9/7zej7P3RrryVHW/DdZAp85MA7Be55p0iUw=="],
|
||||||
|
|
||||||
|
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||||
|
|
||||||
|
"semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
|
||||||
|
|
||||||
|
"shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="],
|
||||||
|
|
||||||
|
"simple-concat": ["simple-concat@1.0.1", "", {}, "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="],
|
||||||
|
|
||||||
|
"simple-get": ["simple-get@4.0.1", "", { "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA=="],
|
||||||
|
|
||||||
|
"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=="],
|
||||||
|
|
||||||
|
"string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
|
||||||
|
|
||||||
|
"strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="],
|
||||||
|
|
||||||
|
"tar-fs": ["tar-fs@2.1.4", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ=="],
|
||||||
|
|
||||||
|
"tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="],
|
||||||
|
|
||||||
|
"tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="],
|
||||||
|
|
||||||
|
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
|
||||||
|
|
||||||
|
"tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="],
|
||||||
|
|
||||||
|
"ts-mixer": ["ts-mixer@6.0.4", "", {}, "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA=="],
|
||||||
|
|
||||||
|
"tsdown": ["tsdown@0.20.3", "", { "dependencies": { "ansis": "^4.2.0", "cac": "^6.7.14", "defu": "^6.1.4", "empathic": "^2.0.0", "hookable": "^6.0.1", "import-without-cache": "^0.2.5", "obug": "^2.1.1", "picomatch": "^4.0.3", "rolldown": "1.0.0-rc.3", "rolldown-plugin-dts": "^0.22.1", "semver": "^7.7.3", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tree-kill": "^1.2.2", "unconfig-core": "^7.4.2", "unrun": "^0.2.27" }, "peerDependencies": { "@arethetypeswrong/core": "^0.18.1", "@vitejs/devtools": "*", "publint": "^0.3.0", "typescript": "^5.0.0", "unplugin-lightningcss": "^0.4.0", "unplugin-unused": "^0.5.0" }, "optionalPeers": ["@arethetypeswrong/core", "@vitejs/devtools", "publint", "typescript", "unplugin-lightningcss", "unplugin-unused"], "bin": { "tsdown": "dist/run.mjs" } }, "sha512-qWOUXSbe4jN8JZEgrkc/uhJpC8VN2QpNu3eZkBWwNuTEjc/Ik1kcc54ycfcQ5QPRHeu9OQXaLfCI3o7pEJgB2w=="],
|
||||||
|
|
||||||
|
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
||||||
|
"tslog": ["tslog@4.10.2", "", {}, "sha512-XuELoRpMR+sq8fuWwX7P0bcj+PRNiicOKDEb3fGNURhxWVyykCi9BNq7c4uVz7h7P0sj8qgBsr5SWS6yBClq3g=="],
|
||||||
|
|
||||||
|
"tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="],
|
||||||
|
|
||||||
|
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||||
|
|
||||||
|
"unconfig-core": ["unconfig-core@7.5.0", "", { "dependencies": { "@quansync/fs": "^1.0.0", "quansync": "^1.0.0" } }, "sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w=="],
|
||||||
|
|
||||||
|
"undici": ["undici@6.21.3", "", {}, "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw=="],
|
||||||
|
|
||||||
|
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
||||||
|
|
||||||
|
"unrun": ["unrun@0.2.27", "", { "dependencies": { "rolldown": "1.0.0-rc.3" }, "peerDependencies": { "synckit": "^0.11.11" }, "optionalPeers": ["synckit"], "bin": { "unrun": "dist/cli.mjs" } }, "sha512-Mmur1UJpIbfxasLOhPRvox/QS4xBiDii71hMP7smfRthGcwFL2OAmYRgduLANOAU4LUkvVamuP+02U+c90jlrw=="],
|
||||||
|
|
||||||
|
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
||||||
|
|
||||||
|
"which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="],
|
||||||
|
|
||||||
|
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
||||||
|
|
||||||
|
"ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="],
|
||||||
|
|
||||||
|
"zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
|
||||||
|
|
||||||
|
"@avocadi/bot-core/cron": ["cron@3.5.0", "", { "dependencies": { "@types/luxon": "~3.4.0", "luxon": "~3.5.0" } }, "sha512-0eYZqCnapmxYcV06uktql93wNWdlTmmBFP2iYz+JPVcQqlyFYcn1lFuIk4R54pkOmE7mcldTAPZv6X5XA4Q46A=="],
|
||||||
|
|
||||||
|
"@avocadi/bot-core/dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
|
||||||
|
|
||||||
|
"@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=="],
|
||||||
|
|
||||||
|
"discord.js/@discordjs/collection": ["@discordjs/collection@1.5.3", "", {}, "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ=="],
|
||||||
|
|
||||||
|
"discord.js/@sapphire/snowflake": ["@sapphire/snowflake@3.5.3", "", {}, "sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ=="],
|
||||||
|
|
||||||
|
"dotenv-expand/dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
|
||||||
|
|
||||||
|
"@avocadi/bot-core/cron/@types/luxon": ["@types/luxon@3.4.2", "", {}, "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA=="],
|
||||||
|
|
||||||
|
"@avocadi/bot-core/cron/luxon": ["luxon@3.5.0", "", {}, "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ=="],
|
||||||
|
|
||||||
|
"@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=="],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
58
core/package.json
Normal file
58
core/package.json
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"name": "@avocadi/bot-core",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "tsdown --watch",
|
||||||
|
"test": "bun test",
|
||||||
|
"build": "tsdown"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "^1.1.14",
|
||||||
|
"better-sqlite3": "^11.7.0",
|
||||||
|
"drizzle-kit": "^0.30.1",
|
||||||
|
"tsdown": "catalog:"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5.7.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@discordjs/rest": "^2.4.0",
|
||||||
|
"cron": "^3.3.1",
|
||||||
|
"discord.js": "^14.16.3",
|
||||||
|
"dotenv": "^16.4.7",
|
||||||
|
"drizzle-orm": "^0.38.3",
|
||||||
|
"i18next": "^25.8.11",
|
||||||
|
"tslog": "^4.10.2",
|
||||||
|
"zod": "catalog:"
|
||||||
|
},
|
||||||
|
"trustedDependencies": [
|
||||||
|
"better-sqlite3",
|
||||||
|
"esbuild"
|
||||||
|
],
|
||||||
|
"exports": {
|
||||||
|
".": "./dist/index.js",
|
||||||
|
"./db": "./dist/db/index.js",
|
||||||
|
"./db/schema": "./dist/db/schema.js",
|
||||||
|
"./entities/channels/channels.schema": "./dist/entities/channels/channels.schema.js",
|
||||||
|
"./entities/channels/voice/voice-channels.service": "./dist/entities/channels/voice/voice-channels.service.js",
|
||||||
|
"./entities/commands/commands.entity": "./dist/entities/commands/commands.entity.js",
|
||||||
|
"./entities/commands/commands.schema": "./dist/entities/commands/commands.schema.js",
|
||||||
|
"./entities/components": "./dist/entities/components/index.js",
|
||||||
|
"./entities/interactions/interactions.schema": "./dist/entities/interactions/interactions.schema.js",
|
||||||
|
"./entities/messages/messages.service": "./dist/entities/messages/messages.service.js",
|
||||||
|
"./entities/roles/roles.schema": "./dist/entities/roles/roles.schema.js",
|
||||||
|
"./entities/roles/roles.service": "./dist/entities/roles/roles.service.js",
|
||||||
|
"./features/accept-user/accept-user.service": "./dist/features/accept-user/accept-user.service.js",
|
||||||
|
"./features/dynamic-voice-channels/dynamic-voice-channels.schema": "./dist/features/dynamic-voice-channels/dynamic-voice-channels.schema.js",
|
||||||
|
"./features/dynamic-voice-channels/dynamic-voice-channels.service": "./dist/features/dynamic-voice-channels/dynamic-voice-channels.service.js",
|
||||||
|
"./features/greeting/greeting.service": "./dist/features/greeting/greeting.service.js",
|
||||||
|
"./features/water-me/water-me.service": "./dist/features/water-me/water-me.service.js",
|
||||||
|
"./lib/common": "./dist/lib/common.js",
|
||||||
|
"./lib/i18n": "./dist/lib/i18n/index.js",
|
||||||
|
"./lib/i18n/i18n.service": "./dist/lib/i18n/i18n.service.js",
|
||||||
|
"./lib/logger": "./dist/lib/logger.js",
|
||||||
|
"./lib/utils": "./dist/lib/utils.js",
|
||||||
|
"./lib/utils.test": "./dist/lib/utils.test.js",
|
||||||
|
"./package.json": "./package.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
137
core/src/actions/customMessage/customMessage.service.ts
Normal file
137
core/src/actions/customMessage/customMessage.service.ts
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
import { Commands, type CommandsType } from "commands/index.ts";
|
||||||
|
import config from "config";
|
||||||
|
import {
|
||||||
|
type CacheType,
|
||||||
|
ChannelType,
|
||||||
|
type ChatInputCommandInteraction,
|
||||||
|
Client,
|
||||||
|
EmbedBuilder,
|
||||||
|
type GuildMember,
|
||||||
|
type Interaction,
|
||||||
|
type Message,
|
||||||
|
type OmitPartialGroupDMChannel,
|
||||||
|
} from "discord.js";
|
||||||
|
import { time } from "drizzle-orm/mysql-core";
|
||||||
|
import client from "lib/client";
|
||||||
|
import { getRandomInt } from "lib/utils";
|
||||||
|
import { createEmbed, customContent } from "./customMessage.components.ts";
|
||||||
|
|
||||||
|
export class CustomMessageService {
|
||||||
|
async handleInteraction(interaction: Interaction<CacheType>) {
|
||||||
|
if (interaction.isChatInputCommand()) {
|
||||||
|
await this.handleChatInputCommand(interaction);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleChatInputCommand(
|
||||||
|
interaction: ChatInputCommandInteraction<CacheType>,
|
||||||
|
) {
|
||||||
|
console.log("accept");
|
||||||
|
const commandName = interaction.commandName as CommandsType;
|
||||||
|
switch (commandName) {
|
||||||
|
case Commands.Enum.embed:
|
||||||
|
await this.customEmbed(interaction);
|
||||||
|
return;
|
||||||
|
case Commands.Enum.message:
|
||||||
|
await this.customMessage(interaction);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkPermission(interaction: ChatInputCommandInteraction<CacheType>) {
|
||||||
|
const userIdCommand = interaction.user.id;
|
||||||
|
if (userIdCommand !== config.discord.myId) {
|
||||||
|
await interaction.reply({
|
||||||
|
content: "you have no permission for that command",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if command done in server
|
||||||
|
async checkIfServer(interaction: ChatInputCommandInteraction<CacheType>) {
|
||||||
|
const guild = interaction.guild;
|
||||||
|
if (!guild) {
|
||||||
|
await interaction.reply({
|
||||||
|
content: "command can only be used on a server",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async customEmbed(interaction: ChatInputCommandInteraction<CacheType>) {
|
||||||
|
const title = interaction.options.getString("title") || " ";
|
||||||
|
const description = interaction.options.getString("description") || " ";
|
||||||
|
const timestamp = interaction.options.getBoolean("timestamp") || false;
|
||||||
|
// return the value
|
||||||
|
console.log(title, description, timestamp);
|
||||||
|
|
||||||
|
// permission check
|
||||||
|
// permission check
|
||||||
|
if (
|
||||||
|
(await this.checkPermission(interaction)) &&
|
||||||
|
(await this.checkIfServer(interaction))
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
const channels = client.channels;
|
||||||
|
const channel = channels.cache.get(interaction.channelId);
|
||||||
|
|
||||||
|
if (channel?.isTextBased() && channel?.isSendable()) {
|
||||||
|
await channel.send({
|
||||||
|
embeds: [createEmbed(title, description, timestamp)],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await interaction.reply({
|
||||||
|
content: "successfully created embed",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("error while creating embed:", error);
|
||||||
|
await interaction.reply({
|
||||||
|
content: "error while creating embed",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async customMessage(interaction: ChatInputCommandInteraction<CacheType>) {
|
||||||
|
const input: string = interaction.options.getString("input") || "";
|
||||||
|
const result = input.replaceAll(";", "\n");
|
||||||
|
|
||||||
|
// return the value
|
||||||
|
console.log(input);
|
||||||
|
|
||||||
|
// permission check && server check
|
||||||
|
if (
|
||||||
|
(await this.checkPermission(interaction)) &&
|
||||||
|
(await this.checkIfServer(interaction))
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
const channels = client.channels;
|
||||||
|
const channel = channels.cache.get(interaction.channelId);
|
||||||
|
|
||||||
|
if (channel?.isTextBased() && channel?.isSendable()) {
|
||||||
|
await channel.send({
|
||||||
|
content: result,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await interaction.reply({
|
||||||
|
content: "successfully created message",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("error while creating message:", error);
|
||||||
|
await interaction.reply({
|
||||||
|
content: "error while creating message",
|
||||||
|
ephemeral: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user