refactor: monorepo structure

NOTE: discord bot moved to apps only
This commit is contained in:
Pihkaal
2025-12-03 14:42:35 +01:00
parent 414509dd6e
commit fd2e2ebd4b
24 changed files with 997 additions and 300 deletions

View File

@@ -1,2 +0,0 @@
node_modules
.env

179
.gitignore vendored
View File

@@ -1,177 +1,2 @@
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
.*_cache
# Logs
logs
_.log
npm-debug.log_
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Caches
.cache
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
# Runtime data
pids
_.pid
_.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
# IntelliJ based IDEs
.idea
# Finder (MacOS) folder config
.DS_Store
node_modules
OLD

4
.prettierignore Normal file
View File

@@ -0,0 +1,4 @@
**/files/
**/dist/
**/node_modules/
pnpm-lock.yaml

View File

@@ -1,10 +0,0 @@
FROM oven/bun:latest
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install
COPY . .
CMD ["bun", "."]

View File

@@ -1 +0,0 @@
# wov-quest-results

View File

@@ -1,7 +1,7 @@
WOV_CLAN_ID=
WOV_API_KEY=
WOV_FETCH_INTERVAL="14400000" # 4 hours
WOV_TRACKING_INTERVAL="432000000" # 12 hours
WOV_TRACKING_INTERVAL="43200000" # 12 hours
QUEST_REWARDS=
QUEST_EXCLUDE=

4
apps/discord-bot/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
.env
node_modules
dist
.cache

View File

@@ -0,0 +1 @@
# @lbf/discord-bot

View File

@@ -0,0 +1,21 @@
{
"name": "@lbf/discord-bot",
"type": "module",
"scripts": {
"dev": "tsx watch src/index.ts",
"start": "node dist/index.js",
"build": "rm -rf dist && tsc --project tsconfig.build.json && tsc-alias --project tsconfig.build.json",
"dev:user": "tsx src/index.ts -- --user"
},
"devDependencies": {
"@types/node": "^22.10.2",
"tsc-alias": "^1.8.16",
"tsx": "^4.19.2",
"typescript": "^5.7.2"
},
"dependencies": {
"discord.js": "^14.21.0",
"dotenv": "^17.2.3",
"zod": "^3.24.4"
}
}

View File

@@ -0,0 +1,34 @@
import { readFile, writeFile, access } from "node:fs/promises";
import { constants } from "node:fs";
const ACCOUNTS_FILE = "./.cache/accounts.json";
export const initAccounts = async (): Promise<void> => {
try {
await access(ACCOUNTS_FILE, constants.F_OK);
} catch {
await writeFile(ACCOUNTS_FILE, "{}");
}
};
export const getAccountBalance = async (playerId: string): Promise<number> => {
const content = await readFile(ACCOUNTS_FILE, "utf-8");
const accounts: Record<string, number> = JSON.parse(content);
if (accounts[playerId]) return accounts[playerId];
accounts[playerId] = 0;
await writeFile(ACCOUNTS_FILE, JSON.stringify(accounts));
return 0;
};
export const setAccountBalance = async (
playerId: string,
balance: number,
): Promise<void> => {
const content = await readFile(ACCOUNTS_FILE, "utf-8");
const accounts: Record<string, number> = JSON.parse(content);
accounts[playerId] = balance;
await writeFile(ACCOUNTS_FILE, JSON.stringify(accounts));
};

View File

@@ -1,5 +1,5 @@
import { env as bunEnv } from "bun";
import { z } from "zod";
import "dotenv/config";
const schema = z.object({
DISCORD_BOT_TOKEN: z.string(),
@@ -24,7 +24,7 @@ const schema = z.object({
.default(""),
});
const result = schema.safeParse(bunEnv);
const result = schema.safeParse(process.env);
if (!result.success) {
console.log("❌ Invalid environments variables:");
console.log(

View File

@@ -1,5 +1,5 @@
import { getAccountBalance, initAccounts, setAccountBalance } from "./account";
import { makeResultEmbed } from "./discord";
import { makeResultEmbed } from "./discordUtils";
import { env } from "./env";
import {
initTracking,
@@ -24,6 +24,7 @@ import {
Message,
Partials,
} from "discord.js";
import * as readline from "node:readline";
// user mode = write in console, send in channel
const flagIndex = process.argv.indexOf("--user");
@@ -208,11 +209,23 @@ client.on("ready", async (client) => {
console.error("ERROR: invalid channel");
process.exit(1);
}
process.stdout.write(`${chan.name} ~ `);
for await (const line of console) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: `${chan.name} ~ `,
});
rl.prompt();
rl.on("line", async (line) => {
await chan.send(line);
process.stdout.write(`${chan.name} ~ `);
}
rl.prompt();
});
rl.on("close", () => {
process.exit(0);
});
} else {
await initAccounts();
await initTracking();

View File

@@ -1,18 +1,22 @@
import { getPlayer } from "./wov";
import { readFile, writeFile, access } from "node:fs/promises";
import { constants } from "node:fs";
const TRACKED_PLAYER_FILE = "./.cache/tracked.json";
type TrackedPlayers = Record<string, string[]>;
export async function initTracking(): Promise<void> {
if (!(await Bun.file(TRACKED_PLAYER_FILE).exists())) {
Bun.file(TRACKED_PLAYER_FILE).write("{}");
try {
await access(TRACKED_PLAYER_FILE, constants.F_OK);
} catch {
await writeFile(TRACKED_PLAYER_FILE, "{}");
}
}
export async function listTrackedPlayers(): Promise<string[]> {
const trackedPlayers: TrackedPlayers =
await Bun.file(TRACKED_PLAYER_FILE).json();
const content = await readFile(TRACKED_PLAYER_FILE, "utf-8");
const trackedPlayers: TrackedPlayers = JSON.parse(content);
return Object.keys(trackedPlayers);
}
@@ -20,13 +24,13 @@ export async function listTrackedPlayers(): Promise<string[]> {
export async function untrackWovPlayer(
playerId: string,
): Promise<{ event: "notTracked" } | { event: "trackerRemoved" }> {
const trackedPlayers: TrackedPlayers =
await Bun.file(TRACKED_PLAYER_FILE).json();
const content = await readFile(TRACKED_PLAYER_FILE, "utf-8");
const trackedPlayers: TrackedPlayers = JSON.parse(content);
if (!trackedPlayers[playerId]) return { event: "notTracked" };
delete trackedPlayers[playerId];
await Bun.file(TRACKED_PLAYER_FILE).write(JSON.stringify(trackedPlayers));
await writeFile(TRACKED_PLAYER_FILE, JSON.stringify(trackedPlayers));
return { event: "trackerRemoved" };
}
@@ -39,8 +43,8 @@ export async function trackWovPlayer(playerId: string): Promise<
| { event: "changed"; oldUsernames: string[]; newUsername: string }
| { event: "none" }
> {
const trackedPlayers: TrackedPlayers =
await Bun.file(TRACKED_PLAYER_FILE).json();
const content = await readFile(TRACKED_PLAYER_FILE, "utf-8");
const trackedPlayers: TrackedPlayers = JSON.parse(content);
const player = await getPlayer(playerId);
if (!player) return { event: "notFound" };
@@ -51,7 +55,7 @@ export async function trackWovPlayer(playerId: string): Promise<
if (!currentUsernames.includes(player.username)) {
currentUsernames.push(player.username);
await Bun.file(TRACKED_PLAYER_FILE).write(JSON.stringify(trackedPlayers));
await writeFile(TRACKED_PLAYER_FILE, JSON.stringify(trackedPlayers));
return {
event: "changed",
@@ -65,7 +69,7 @@ export async function trackWovPlayer(playerId: string): Promise<
}
} else {
trackedPlayers[playerId] = [player.username];
await Bun.file(TRACKED_PLAYER_FILE).write(JSON.stringify(trackedPlayers));
await writeFile(TRACKED_PLAYER_FILE, JSON.stringify(trackedPlayers));
return { event: "registered" };
}
}

View File

@@ -1,5 +1,6 @@
import { env } from "./env";
import { mkdir } from "node:fs/promises";
import { mkdir, readFile, writeFile, access } from "node:fs/promises";
import { constants } from "node:fs";
export type QuestResult = {
quest: {
@@ -32,35 +33,42 @@ export const checkForNewQuest = async (): Promise<QuestResult | null> => {
const lastQuest = await getLatestQuest();
const lastId = lastQuest.quest.id;
const cacheFile = Bun.file(".cache/.quest_cache");
const cacheFilePath = ".cache/.quest_cache";
await mkdir(".cache", { recursive: true });
if (await cacheFile.exists()) {
const cachedQuestId = await cacheFile.text();
try {
await access(cacheFilePath, constants.F_OK);
const cachedQuestId = await readFile(cacheFilePath, "utf-8");
if (cachedQuestId === lastId || cachedQuestId === "IGNORE") {
return null;
}
} catch {
// File doesn't exist, continue
}
await cacheFile.write(lastId);
await writeFile(cacheFilePath, lastId);
return lastQuest;
};
export const getClanMembers = async (): Promise<
Array<{ playerId: string; username: string }>
> => {
const cacheFile = Bun.file(".clan_members_cache");
const cacheFilePath = ".clan_members_cache";
await mkdir(".cache", { recursive: true });
let cached: {
timestamp: number;
data: Array<{ playerId: string; username: string }>;
} | null = null;
if (await cacheFile.exists()) {
try {
cached = JSON.parse(await cacheFile.text());
if (cached && Date.now() - cached.timestamp < 60 * 60 * 1000) {
return cached.data;
}
} catch {}
try {
await access(cacheFilePath, constants.F_OK);
const content = await readFile(cacheFilePath, "utf-8");
cached = JSON.parse(content);
if (cached && Date.now() - cached.timestamp < 60 * 60 * 1000) {
return cached.data;
}
} catch {
// File doesn't exist or is invalid, continue
}
const response = await fetch(
@@ -74,7 +82,10 @@ export const getClanMembers = async (): Promise<
playerId: string;
username: string;
}>;
await cacheFile.write(JSON.stringify({ timestamp: Date.now(), data }));
await writeFile(
cacheFilePath,
JSON.stringify({ timestamp: Date.now(), data }),
);
return data;
};

View File

@@ -0,0 +1,16 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": false,
"noEmitOnError": true,
"outDir": "dist",
"rootDir": "src",
"sourceMap": true
},
"tsc-alias": {
"resolveFullPaths": true,
"verbose": false
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}

View File

@@ -1,25 +1,20 @@
{
"compilerOptions": {
// Enable latest features
"lib": ["ESNext", "DOM"],
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false,

BIN
bun.lockb

Binary file not shown.

View File

@@ -1,29 +0,0 @@
services:
bot:
image: pihkaal/wov-quest-result:latest
networks:
- web
environment:
- WOV_CLAN_ID
- WOV_API_KEY
- WOV_FETCH_INTERVAL
- WOV_TRACKING_INTERVAL
- QUEST_REWARDS
- QUEST_EXCLUDE
- DISCORD_MENTION
- DISCORD_REWARDS_GIVER
- DISCORD_REWARDS_CHANNEL
- DISCORD_BOT_TOKEN
- DISCORD_ADMIN_MENTION
- DISCORD_ADMIN_CHANNEL
- DISCORD_TRACKING_CHANNEL
volumes:
- cache:/app/.cache
restart: always
networks:
web:
external: true
volumes:
cache:

View File

@@ -1,19 +1,10 @@
{
"name": "wov-quest-results",
"module": "src/index.ts",
"type": "module",
"name": "lbf",
"packageManager": "pnpm@10.20.0",
"scripts": {
"format": "prettier --write --cache ."
},
"devDependencies": {
"@types/bun": "latest",
"prettier": "^3.5.3"
},
"peerDependencies": {
"typescript": "^5.0.0"
},
"dependencies": {
"discord.js": "^14.21.0",
"zod": "^3.24.4"
"prettier": "3.6.2"
}
}

841
pnpm-lock.yaml generated Normal file
View File

@@ -0,0 +1,841 @@
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.:
dependencies:
prettier:
specifier: 3.6.2
version: 3.6.2
apps/discord-bot:
dependencies:
discord.js:
specifier: ^14.21.0
version: 14.25.1
dotenv:
specifier: ^17.2.3
version: 17.2.3
zod:
specifier: ^3.24.4
version: 3.25.76
devDependencies:
'@types/node':
specifier: ^22.10.2
version: 22.19.1
tsc-alias:
specifier: ^1.8.16
version: 1.8.16
tsx:
specifier: ^4.19.2
version: 4.21.0
typescript:
specifier: ^5.7.2
version: 5.9.3
packages:
'@discordjs/builders@1.13.1':
resolution: {integrity: sha512-cOU0UDHc3lp/5nKByDxkmRiNZBpdp0kx55aarbiAfakfKJHlxv/yFW1zmIqCAmwH5CRlrH9iMFKJMpvW4DPB+w==}
engines: {node: '>=16.11.0'}
'@discordjs/collection@1.5.3':
resolution: {integrity: sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==}
engines: {node: '>=16.11.0'}
'@discordjs/collection@2.1.1':
resolution: {integrity: sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==}
engines: {node: '>=18'}
'@discordjs/formatters@0.6.2':
resolution: {integrity: sha512-y4UPwWhH6vChKRkGdMB4odasUbHOUwy7KL+OVwF86PvT6QVOwElx+TiI1/6kcmcEe+g5YRXJFiXSXUdabqZOvQ==}
engines: {node: '>=16.11.0'}
'@discordjs/rest@2.6.0':
resolution: {integrity: sha512-RDYrhmpB7mTvmCKcpj+pc5k7POKszS4E2O9TYc+U+Y4iaCP+r910QdO43qmpOja8LRr1RJ0b3U+CqVsnPqzf4w==}
engines: {node: '>=18'}
'@discordjs/util@1.2.0':
resolution: {integrity: sha512-3LKP7F2+atl9vJFhaBjn4nOaSWahZ/yWjOvA4e5pnXkt2qyXRCHLxoBQy81GFtLGCq7K9lPm9R517M1U+/90Qg==}
engines: {node: '>=18'}
'@discordjs/ws@1.2.3':
resolution: {integrity: sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw==}
engines: {node: '>=16.11.0'}
'@esbuild/aix-ppc64@0.27.0':
resolution: {integrity: sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
'@esbuild/android-arm64@0.27.0':
resolution: {integrity: sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
'@esbuild/android-arm@0.27.0':
resolution: {integrity: sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
'@esbuild/android-x64@0.27.0':
resolution: {integrity: sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
'@esbuild/darwin-arm64@0.27.0':
resolution: {integrity: sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-x64@0.27.0':
resolution: {integrity: sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
'@esbuild/freebsd-arm64@0.27.0':
resolution: {integrity: sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-x64@0.27.0':
resolution: {integrity: sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
'@esbuild/linux-arm64@0.27.0':
resolution: {integrity: sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm@0.27.0':
resolution: {integrity: sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
'@esbuild/linux-ia32@0.27.0':
resolution: {integrity: sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
'@esbuild/linux-loong64@0.27.0':
resolution: {integrity: sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
'@esbuild/linux-mips64el@0.27.0':
resolution: {integrity: sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
'@esbuild/linux-ppc64@0.27.0':
resolution: {integrity: sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
'@esbuild/linux-riscv64@0.27.0':
resolution: {integrity: sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
'@esbuild/linux-s390x@0.27.0':
resolution: {integrity: sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
'@esbuild/linux-x64@0.27.0':
resolution: {integrity: sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
'@esbuild/netbsd-arm64@0.27.0':
resolution: {integrity: sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
'@esbuild/netbsd-x64@0.27.0':
resolution: {integrity: sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
'@esbuild/openbsd-arm64@0.27.0':
resolution: {integrity: sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
'@esbuild/openbsd-x64@0.27.0':
resolution: {integrity: sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
'@esbuild/openharmony-arm64@0.27.0':
resolution: {integrity: sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
'@esbuild/sunos-x64@0.27.0':
resolution: {integrity: sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
'@esbuild/win32-arm64@0.27.0':
resolution: {integrity: sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
'@esbuild/win32-ia32@0.27.0':
resolution: {integrity: sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
'@esbuild/win32-x64@0.27.0':
resolution: {integrity: sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
'@nodelib/fs.stat@2.0.5':
resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
engines: {node: '>= 8'}
'@nodelib/fs.walk@1.2.8':
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
'@sapphire/async-queue@1.5.5':
resolution: {integrity: sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg==}
engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
'@sapphire/shapeshift@4.0.0':
resolution: {integrity: sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg==}
engines: {node: '>=v16'}
'@sapphire/snowflake@3.5.3':
resolution: {integrity: sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ==}
engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
'@types/node@22.19.1':
resolution: {integrity: sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==}
'@types/ws@8.18.1':
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
'@vladfrangu/async_event_emitter@2.4.7':
resolution: {integrity: sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g==}
engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
anymatch@3.1.3:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
array-union@2.1.0:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'}
binary-extensions@2.3.0:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
braces@3.0.3:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
commander@9.5.0:
resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
engines: {node: ^12.20.0 || >=14}
dir-glob@3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
discord-api-types@0.38.36:
resolution: {integrity: sha512-qrbUbjjwtyeBg5HsAlm1C859epfOyiLjPqAOzkdWlCNsZCWJrertnETF/NwM8H+waMFU58xGSc5eXUfXah+WTQ==}
discord.js@14.25.1:
resolution: {integrity: sha512-2l0gsPOLPs5t6GFZfQZKnL1OJNYFcuC/ETWsW4VtKVD/tg4ICa9x+jb9bkPffkMdRpRpuUaO/fKkHCBeiCKh8g==}
engines: {node: '>=18'}
dotenv@17.2.3:
resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
engines: {node: '>=12'}
esbuild@0.27.0:
resolution: {integrity: sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==}
engines: {node: '>=18'}
hasBin: true
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
fast-glob@3.3.3:
resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
engines: {node: '>=8.6.0'}
fastq@1.19.1:
resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
fill-range@7.1.1:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
get-tsconfig@4.13.0:
resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==}
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
globby@11.1.0:
resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
engines: {node: '>=10'}
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
lodash.snakecase@4.1.1:
resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==}
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
magic-bytes.js@1.12.1:
resolution: {integrity: sha512-ThQLOhN86ZkJ7qemtVRGYM+gRgR8GEXNli9H/PMvpnZsE44Xfh3wx9kGJaldg314v85m+bFW6WBMaVHJc/c3zA==}
merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
micromatch@4.0.8:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'}
mylas@2.1.14:
resolution: {integrity: sha512-BzQguy9W9NJgoVn2mRWzbFrFWWztGCcng2QI9+41frfk+Athwgx3qhqhvStz7ExeUUu7Kzw427sNzHpEZNINog==}
engines: {node: '>=16.0.0'}
normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
plimit-lit@1.6.1:
resolution: {integrity: sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA==}
engines: {node: '>=12'}
prettier@3.6.2:
resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
engines: {node: '>=14'}
hasBin: true
queue-lit@1.5.2:
resolution: {integrity: sha512-tLc36IOPeMAubu8BkW8YDBV+WyIgKlYU7zUNs0J5Vk9skSZ4JfGlPOqplP0aHdfv7HL0B2Pg6nwiq60Qc6M2Hw==}
engines: {node: '>=12'}
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
resolve-pkg-maps@1.0.0:
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
reusify@1.1.0:
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
ts-mixer@6.0.4:
resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==}
tsc-alias@1.8.16:
resolution: {integrity: sha512-QjCyu55NFyRSBAl6+MTFwplpFcnm2Pq01rR/uxfqJoLMm6X3O14KEGtaSDZpJYaE1bJBGDjD0eSuiIWPe2T58g==}
engines: {node: '>=16.20.2'}
hasBin: true
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
tsx@4.21.0:
resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==}
engines: {node: '>=18.0.0'}
hasBin: true
typescript@5.9.3:
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
engines: {node: '>=14.17'}
hasBin: true
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
undici@6.21.3:
resolution: {integrity: sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==}
engines: {node: '>=18.17'}
ws@8.18.3:
resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: '>=5.0.2'
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
zod@3.25.76:
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
snapshots:
'@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.36
fast-deep-equal: 3.1.3
ts-mixer: 6.0.4
tslib: 2.8.1
'@discordjs/collection@1.5.3': {}
'@discordjs/collection@2.1.1': {}
'@discordjs/formatters@0.6.2':
dependencies:
discord-api-types: 0.38.36
'@discordjs/rest@2.6.0':
dependencies:
'@discordjs/collection': 2.1.1
'@discordjs/util': 1.2.0
'@sapphire/async-queue': 1.5.5
'@sapphire/snowflake': 3.5.3
'@vladfrangu/async_event_emitter': 2.4.7
discord-api-types: 0.38.36
magic-bytes.js: 1.12.1
tslib: 2.8.1
undici: 6.21.3
'@discordjs/util@1.2.0':
dependencies:
discord-api-types: 0.38.36
'@discordjs/ws@1.2.3':
dependencies:
'@discordjs/collection': 2.1.1
'@discordjs/rest': 2.6.0
'@discordjs/util': 1.2.0
'@sapphire/async-queue': 1.5.5
'@types/ws': 8.18.1
'@vladfrangu/async_event_emitter': 2.4.7
discord-api-types: 0.38.36
tslib: 2.8.1
ws: 8.18.3
transitivePeerDependencies:
- bufferutil
- utf-8-validate
'@esbuild/aix-ppc64@0.27.0':
optional: true
'@esbuild/android-arm64@0.27.0':
optional: true
'@esbuild/android-arm@0.27.0':
optional: true
'@esbuild/android-x64@0.27.0':
optional: true
'@esbuild/darwin-arm64@0.27.0':
optional: true
'@esbuild/darwin-x64@0.27.0':
optional: true
'@esbuild/freebsd-arm64@0.27.0':
optional: true
'@esbuild/freebsd-x64@0.27.0':
optional: true
'@esbuild/linux-arm64@0.27.0':
optional: true
'@esbuild/linux-arm@0.27.0':
optional: true
'@esbuild/linux-ia32@0.27.0':
optional: true
'@esbuild/linux-loong64@0.27.0':
optional: true
'@esbuild/linux-mips64el@0.27.0':
optional: true
'@esbuild/linux-ppc64@0.27.0':
optional: true
'@esbuild/linux-riscv64@0.27.0':
optional: true
'@esbuild/linux-s390x@0.27.0':
optional: true
'@esbuild/linux-x64@0.27.0':
optional: true
'@esbuild/netbsd-arm64@0.27.0':
optional: true
'@esbuild/netbsd-x64@0.27.0':
optional: true
'@esbuild/openbsd-arm64@0.27.0':
optional: true
'@esbuild/openbsd-x64@0.27.0':
optional: true
'@esbuild/openharmony-arm64@0.27.0':
optional: true
'@esbuild/sunos-x64@0.27.0':
optional: true
'@esbuild/win32-arm64@0.27.0':
optional: true
'@esbuild/win32-ia32@0.27.0':
optional: true
'@esbuild/win32-x64@0.27.0':
optional: true
'@nodelib/fs.scandir@2.1.5':
dependencies:
'@nodelib/fs.stat': 2.0.5
run-parallel: 1.2.0
'@nodelib/fs.stat@2.0.5': {}
'@nodelib/fs.walk@1.2.8':
dependencies:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.19.1
'@sapphire/async-queue@1.5.5': {}
'@sapphire/shapeshift@4.0.0':
dependencies:
fast-deep-equal: 3.1.3
lodash: 4.17.21
'@sapphire/snowflake@3.5.3': {}
'@types/node@22.19.1':
dependencies:
undici-types: 6.21.0
'@types/ws@8.18.1':
dependencies:
'@types/node': 22.19.1
'@vladfrangu/async_event_emitter@2.4.7': {}
anymatch@3.1.3:
dependencies:
normalize-path: 3.0.0
picomatch: 2.3.1
array-union@2.1.0: {}
binary-extensions@2.3.0: {}
braces@3.0.3:
dependencies:
fill-range: 7.1.1
chokidar@3.6.0:
dependencies:
anymatch: 3.1.3
braces: 3.0.3
glob-parent: 5.1.2
is-binary-path: 2.1.0
is-glob: 4.0.3
normalize-path: 3.0.0
readdirp: 3.6.0
optionalDependencies:
fsevents: 2.3.3
commander@9.5.0: {}
dir-glob@3.0.1:
dependencies:
path-type: 4.0.0
discord-api-types@0.38.36: {}
discord.js@14.25.1:
dependencies:
'@discordjs/builders': 1.13.1
'@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.36
fast-deep-equal: 3.1.3
lodash.snakecase: 4.1.1
magic-bytes.js: 1.12.1
tslib: 2.8.1
undici: 6.21.3
transitivePeerDependencies:
- bufferutil
- utf-8-validate
dotenv@17.2.3: {}
esbuild@0.27.0:
optionalDependencies:
'@esbuild/aix-ppc64': 0.27.0
'@esbuild/android-arm': 0.27.0
'@esbuild/android-arm64': 0.27.0
'@esbuild/android-x64': 0.27.0
'@esbuild/darwin-arm64': 0.27.0
'@esbuild/darwin-x64': 0.27.0
'@esbuild/freebsd-arm64': 0.27.0
'@esbuild/freebsd-x64': 0.27.0
'@esbuild/linux-arm': 0.27.0
'@esbuild/linux-arm64': 0.27.0
'@esbuild/linux-ia32': 0.27.0
'@esbuild/linux-loong64': 0.27.0
'@esbuild/linux-mips64el': 0.27.0
'@esbuild/linux-ppc64': 0.27.0
'@esbuild/linux-riscv64': 0.27.0
'@esbuild/linux-s390x': 0.27.0
'@esbuild/linux-x64': 0.27.0
'@esbuild/netbsd-arm64': 0.27.0
'@esbuild/netbsd-x64': 0.27.0
'@esbuild/openbsd-arm64': 0.27.0
'@esbuild/openbsd-x64': 0.27.0
'@esbuild/openharmony-arm64': 0.27.0
'@esbuild/sunos-x64': 0.27.0
'@esbuild/win32-arm64': 0.27.0
'@esbuild/win32-ia32': 0.27.0
'@esbuild/win32-x64': 0.27.0
fast-deep-equal@3.1.3: {}
fast-glob@3.3.3:
dependencies:
'@nodelib/fs.stat': 2.0.5
'@nodelib/fs.walk': 1.2.8
glob-parent: 5.1.2
merge2: 1.4.1
micromatch: 4.0.8
fastq@1.19.1:
dependencies:
reusify: 1.1.0
fill-range@7.1.1:
dependencies:
to-regex-range: 5.0.1
fsevents@2.3.3:
optional: true
get-tsconfig@4.13.0:
dependencies:
resolve-pkg-maps: 1.0.0
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
globby@11.1.0:
dependencies:
array-union: 2.1.0
dir-glob: 3.0.1
fast-glob: 3.3.3
ignore: 5.3.2
merge2: 1.4.1
slash: 3.0.0
ignore@5.3.2: {}
is-binary-path@2.1.0:
dependencies:
binary-extensions: 2.3.0
is-extglob@2.1.1: {}
is-glob@4.0.3:
dependencies:
is-extglob: 2.1.1
is-number@7.0.0: {}
lodash.snakecase@4.1.1: {}
lodash@4.17.21: {}
magic-bytes.js@1.12.1: {}
merge2@1.4.1: {}
micromatch@4.0.8:
dependencies:
braces: 3.0.3
picomatch: 2.3.1
mylas@2.1.14: {}
normalize-path@3.0.0: {}
path-type@4.0.0: {}
picomatch@2.3.1: {}
plimit-lit@1.6.1:
dependencies:
queue-lit: 1.5.2
prettier@3.6.2: {}
queue-lit@1.5.2: {}
queue-microtask@1.2.3: {}
readdirp@3.6.0:
dependencies:
picomatch: 2.3.1
resolve-pkg-maps@1.0.0: {}
reusify@1.1.0: {}
run-parallel@1.2.0:
dependencies:
queue-microtask: 1.2.3
slash@3.0.0: {}
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
ts-mixer@6.0.4: {}
tsc-alias@1.8.16:
dependencies:
chokidar: 3.6.0
commander: 9.5.0
get-tsconfig: 4.13.0
globby: 11.1.0
mylas: 2.1.14
normalize-path: 3.0.0
plimit-lit: 1.6.1
tslib@2.8.1: {}
tsx@4.21.0:
dependencies:
esbuild: 0.27.0
get-tsconfig: 4.13.0
optionalDependencies:
fsevents: 2.3.3
typescript@5.9.3: {}
undici-types@6.21.0: {}
undici@6.21.3: {}
ws@8.18.3: {}
zod@3.25.76: {}

6
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,6 @@
packages:
- packages/*
- apps/*
onlyBuiltDependencies:
- esbuild

View File

@@ -1,27 +0,0 @@
const ACCOUNTS_FILE = "./.cache/accounts.json";
export const initAccounts = async (): Promise<void> => {
if (!(await Bun.file(ACCOUNTS_FILE).exists())) {
Bun.file(ACCOUNTS_FILE).write("{}");
}
};
export const getAccountBalance = async (playerId: string): Promise<number> => {
const accounts: Record<string, number> = await Bun.file(ACCOUNTS_FILE).json();
if (accounts[playerId]) return accounts[playerId];
accounts[playerId] = 0;
await Bun.file(ACCOUNTS_FILE).write(JSON.stringify(accounts));
return 0;
};
export const setAccountBalance = async (
playerId: string,
balance: number,
): Promise<void> => {
const accounts: Record<string, number> = await Bun.file(ACCOUNTS_FILE).json();
accounts[playerId] = balance;
await Bun.file(ACCOUNTS_FILE).write(JSON.stringify(accounts));
};