Initialize apps/bot and other cleanup
This commit is contained in:
@@ -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`.
|
||||
@@ -0,0 +1,15 @@
|
||||
# bot
|
||||
|
||||
To install dependencies:
|
||||
|
||||
```bash
|
||||
bun install
|
||||
```
|
||||
|
||||
To run:
|
||||
|
||||
```bash
|
||||
bun run index.ts
|
||||
```
|
||||
|
||||
This project was created using `bun init` in bun v1.3.14. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "@blade-and-brawn/bot",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"devDependencies": {},
|
||||
"peerDependencies": {},
|
||||
"dependencies": {
|
||||
"discord.js": "^14.27.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "bun run src/index.ts"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Client, Events, GatewayIntentBits } from 'discord.js';
|
||||
import { CommandService } from './services/cmd/service';
|
||||
|
||||
const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent] });
|
||||
|
||||
// SERVICES
|
||||
// -----------------------
|
||||
const s = (() => {
|
||||
const Commands = new CommandService(client);
|
||||
return { Commands };
|
||||
})();
|
||||
|
||||
client.once(Events.ClientReady, async (readyClient) => {
|
||||
// Initialize
|
||||
await s.Commands.init();
|
||||
|
||||
console.log(`Ready! Logged in as ${readyClient.user.tag}`);
|
||||
});
|
||||
|
||||
client.on("guildMemberAdd", async (guildMember) => {
|
||||
});
|
||||
|
||||
client.on("messageCreate", async (message) => {
|
||||
if (message.author.bot) return;
|
||||
|
||||
const command = s.Commands.parse(message);
|
||||
if (command) command.execute(message);
|
||||
});
|
||||
|
||||
client.login(Bun.env.BOT_TOKEN);
|
||||
@@ -0,0 +1,10 @@
|
||||
import type { Message } from "discord.js";
|
||||
import type { Command } from "../service";
|
||||
|
||||
export default {
|
||||
name: "stats",
|
||||
description: "View your fitness statistics!",
|
||||
execute: async (message: Message) => {
|
||||
console.log("Stats executed");
|
||||
}
|
||||
} as Command;
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { Client, Message } from "discord.js";
|
||||
import { readdir } from "fs/promises";
|
||||
|
||||
const CMD_PREFIX = ".";
|
||||
|
||||
export interface Command {
|
||||
name: string,
|
||||
description: string,
|
||||
execute: (message: Message) => void | Promise<void>
|
||||
}
|
||||
|
||||
export class CommandService {
|
||||
private client: Client
|
||||
private registry: Record<string, Command> = {}
|
||||
|
||||
constructor(client: Client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
async init() {
|
||||
const commands = await Promise.all(
|
||||
(await readdir(`${import.meta.dir}/registry`)).map(async file => (await import(`./registry/${file}`)).default as Command)
|
||||
);
|
||||
for (const command of commands)
|
||||
this.registry[command.name] = command;
|
||||
};
|
||||
|
||||
parse(message: Message): Command | undefined {
|
||||
if (!message.content.startsWith(CMD_PREFIX)) return;
|
||||
const name = message.content.slice(CMD_PREFIX.length).split(/\s+/)[0];
|
||||
return this.registry[name ?? ""];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json"
|
||||
}
|
||||
@@ -5,7 +5,6 @@
|
||||
"@blade-and-brawn/api": "workspace:*",
|
||||
"@sveltejs/kit": "^2.70.2",
|
||||
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
||||
"@types/bun": "^1.3.14",
|
||||
"elysia": "^1.4.29",
|
||||
"svelte": "^5.56.9",
|
||||
"svelte-adapter-bun": "^1.0.1",
|
||||
|
||||
Reference in New Issue
Block a user