diff --git a/.env.example b/.env.example index 0552924..747feb1 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,5 @@ +NODE_ENV=dev # Your node environment (prod, dev) + # Selfbot options TOKEN = "" # Your Discord self-bot token PREFIX = "$" # The prefix used to trigger your self-bot commands diff --git a/.gitignore b/.gitignore index 07bc5ab..d6e2f51 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,8 @@ node_modules/ dist/ .env bun.lockb +*lock.json videos/ tmp/ *.sock -cookies.txt \ No newline at end of file +cookies.txt diff --git a/package.json b/package.json index acdff00..0bbcca2 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,12 @@ "start:node": "node dist/index.js", "server": "bun src/server/index.ts", "server:node": "node dist/server/index.js", + "dev": "tsx watch src/index.ts", + "dev:server": "tsx watch src/server/index.ts", + "prebuild": "rimraf dist && npm run type-check", "build": "tsc", + "build:only": "tsc", + "type-check": "tsc --noEmit", "watch": "tsc -w", "gen-hash": "bun src/utils/gen-hash.ts", "gen-hash:node": "node dist/utils/gen-hash.js" @@ -18,8 +23,6 @@ "license": "MIT", "dependencies": { "@dank074/discord-video-stream": "6.0.0", - "@types/bcrypt": "^6.0.0", - "@types/bun": "^1.3.10", "argon2": "^0.44.0", "axios": "^1.13.6", "bcrypt": "^6.0.0", @@ -37,9 +40,13 @@ "winston": "^3.19.0" }, "devDependencies": { + "@types/bcrypt": "^6.0.0", + "@types/bun": "^1.3.10", "@types/express": "^5.0.6", "@types/express-session": "^1.18.2", "@types/multer": "^2.1.0", + "rimraf": "^6.1.3", + "tsx": "^4.22.3", "typescript": "^5.9.3" } } diff --git a/src/commands/manager.ts b/src/commands/manager.ts index 65129c1..e4943a8 100644 --- a/src/commands/manager.ts +++ b/src/commands/manager.ts @@ -14,9 +14,10 @@ export class CommandManager { } private async loadCommands(): Promise { - // Prefer src for Bun (TypeScript native), dist for Node.js (compiled JS) + // Prefer src for Bun (TypeScript native) or dev environment, dist for Node.js (compiled JS) const isBun = typeof Bun !== 'undefined'; - const commandsPath = path.join(process.cwd(), isBun ? 'src' : 'dist', 'commands'); + const isDev = !config.isProduction; + const commandsPath = path.join(process.cwd(), (isBun || isDev) ? 'src' : 'dist', 'commands'); if (!commandsPath) { logger.error('Could not find commands directory in either dist/ or src/'); @@ -87,6 +88,10 @@ export class CommandManager { return Array.from(this.commands.values()); } + public exists(name: string): boolean { + return this.commands.has(name.toLowerCase()) || this.aliases.has(name.toLowerCase()); + } + public async executeCommand(commandName: string, context: CommandContext): Promise { const command = this.getCommand(commandName); diff --git a/src/config.ts b/src/config.ts index 4c214ac..636cc6d 100644 --- a/src/config.ts +++ b/src/config.ts @@ -64,6 +64,10 @@ function parseAdminIds(value: string): string[] { } export default { + get isProduction() { + return process.env.NODE_ENV === 'production'; + }, + // Selfbot options token: process.env.TOKEN || '', prefix: process.env.PREFIX || '', diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts index a464132..ab40142 100644 --- a/src/events/messageCreate.ts +++ b/src/events/messageCreate.ts @@ -27,6 +27,12 @@ export async function handleMessageCreate( const commandName = args.shift()!.toLowerCase(); + if (!commandManager.exists(commandName)) { + await message.react('❌'); + await message.reply(`❌ **Error**: Unknown command. Use \`${config.prefix}help\` to see available commands.`); + return; + } + const context: CommandContext = { message, args, @@ -39,6 +45,6 @@ export async function handleMessageCreate( if (!executed) { await message.react('❌'); - await message.reply(`❌ **Error**: Unknown command. Use \`${config.prefix}help\` to see available commands.`); + await message.reply(`❌ **Error**: Failed to execute command. Please check the command usage and try again.`); } } diff --git a/src/server/index.ts b/src/server/index.ts index 3c92c68..c8b7ebb 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -16,7 +16,7 @@ import dashboardRoutes from "./routes/dashboard.js"; import uploadRoutes from "./routes/upload.js"; import previewRoutes from "./routes/preview.js"; -const app = express(); +const app: express.Application = express(); // Configure EJS templating engine app.set('view engine', 'ejs'); diff --git a/src/server/routes/auth.ts b/src/server/routes/auth.ts index 31a7cfa..66562ad 100644 --- a/src/server/routes/auth.ts +++ b/src/server/routes/auth.ts @@ -1,10 +1,10 @@ -import { Router } from 'express'; +import express from 'express'; import bcrypt from 'bcrypt'; import argon2 from 'argon2'; import config from '../../config.js'; import logger from '../../utils/logger.js'; -const router = Router(); +const router: express.Router = express.Router(); // Login route - GET router.get("/login", (req, res) => { diff --git a/src/server/routes/dashboard.ts b/src/server/routes/dashboard.ts index 208b156..6d60916 100644 --- a/src/server/routes/dashboard.ts +++ b/src/server/routes/dashboard.ts @@ -1,11 +1,11 @@ -import { Router } from 'express'; +import express from 'express'; import fs from 'fs'; import path from 'path'; import config from '../../config.js'; import logger from '../../utils/logger.js'; import { prettySize } from '../utils/helpers.js'; -const router = Router(); +const router: express.Router = express.Router(); // Main dashboard route router.get("/", (req, res) => { diff --git a/src/server/routes/preview.ts b/src/server/routes/preview.ts index 0372e39..8a746ae 100644 --- a/src/server/routes/preview.ts +++ b/src/server/routes/preview.ts @@ -1,13 +1,12 @@ -import { Router } from 'express'; +import express from 'express'; import fs from 'fs'; import path from 'path'; import ffmpeg from 'fluent-ffmpeg'; import config from '../../config.js'; import logger from '../../utils/logger.js'; import { ffmpegScreenshot } from '../../utils/ffmpeg.js'; -import { stringify } from '../utils/helpers.js'; -const router = Router(); +const router: express.Router = express.Router(); // Preview route router.get("/preview/:file", (req, res) => { diff --git a/src/server/routes/upload.ts b/src/server/routes/upload.ts index 272281e..5295bd7 100644 --- a/src/server/routes/upload.ts +++ b/src/server/routes/upload.ts @@ -1,4 +1,4 @@ -import { Router } from 'express'; +import express from 'express'; import axios from 'axios'; import https from 'https'; import fs from 'fs'; @@ -7,7 +7,7 @@ import config from '../../config.js'; import logger from '../../utils/logger.js'; import { upload } from '../middleware/multer.js'; -const router = Router(); +const router: express.Router = express.Router(); const agent = new https.Agent({ rejectUnauthorized: false }); // Upload route - local file with progress support @@ -29,7 +29,7 @@ router.post("/api/remote_upload", upload.single("link"), async (req, res) => { try { // First, get the file info to determine size const headResponse = await axios.head(link, { httpsAgent: agent }); - const totalSize = parseInt(headResponse.headers['content-length'], 10); + const totalSize = Number(headResponse.headers['content-length'] || 0); // Set up progress tracking let downloaded = 0; diff --git a/tsconfig.json b/tsconfig.json index eb42434..5f5d79e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -24,6 +24,8 @@ "strictNullChecks": false, /* When type checking, take into account null and undefined. */ "skipLibCheck": true, /* Skip type checking all .d.ts files. */ + "types": ["bun"], + "allowJs": true, "declaration": true }