diff --git a/.gitignore b/.gitignore index 96fab4f..0feb86b 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,9 @@ out/ build dist +# Environment Variables +.env* +!.env.example # Debug npm-debug.log* diff --git a/apps/client/package.json b/apps/client/package.json index 95fb962..144da0a 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "next dev", + "dev": "next dev -p 5173", "build": "next build", "start": "next start", "lint": "biome check", @@ -48,4 +48,4 @@ "sharp", "unrs-resolver" ] -} \ No newline at end of file +} diff --git a/apps/server/lib/redis/index.ts b/apps/server/lib/redis/index.ts deleted file mode 100644 index dfbe2ef..0000000 --- a/apps/server/lib/redis/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { RedisClient } from "bun"; - -type RedisOptions = { - url: string; - options?: Bun.RedisOptions; -}; - -class Redis { - private client: RedisClient; - - constructor(options: RedisOptions) { - this.client = new RedisClient(options.url, options.options); - } - - async set(key: string, value: string, expireInSeconds?: number) { - if (expireInSeconds) { - await this.client.set(key, value, "EX", expireInSeconds); - } else { - await this.client.set(key, value); - } - } - - async get(key: string): Promise { - const value = await this.client.get(key); - return value ? (JSON.parse(value) as T) : null; - } - - async del(key: string) { - await this.client.del(key); - } - - async exists(key: string): Promise { - return await this.client.exists(key); - } -} - -export const redis = new Redis({ - url: process.env.REDIS_URL || "redis://localhost:6379", -}); \ No newline at end of file diff --git a/apps/server/lib/s3/index.ts b/apps/server/lib/s3/index.ts deleted file mode 100644 index b7712ce..0000000 --- a/apps/server/lib/s3/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { S3Client } from "bun"; - -interface S3Options { - accessKeyId: string - secretAccessKey: string - bucket: string - endpoint: string -} - -class S3 { - private client: S3Client; - - constructor(options: S3Options) { - this.client = new S3Client(options); - } - - async upload(key: string, body: File) { - return await this.client.write(key, body); - } - - async get(key: string) { - return await this.client.file(key); - } - - async delete(key: string) { - return await this.client.delete(key); - } - - async presignedUrl(key: string, expiresIn: number = 3600) { - return await this.client.presign(key, { expiresIn }); - } -} - -export const s3 = new S3({ - accessKeyId: process.env.S3_ACCESS_KEY_ID!, - secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!, - bucket: process.env.S3_BUCKET!, - endpoint: process.env.S3_ENDPOINT!, -}); \ No newline at end of file diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts index 39b65ab..b0e175f 100644 --- a/apps/server/src/index.ts +++ b/apps/server/src/index.ts @@ -1,7 +1,12 @@ import { auth } from "../lib/auth"; import { Elysia, t } from "elysia"; -const app = new Elysia().mount("/auth", auth.handler).listen(3000); +const app = new Elysia() + .mount("/auth", auth.handler) + .get("/health", () => "OK", { + response: t.String(), + }) + .listen(3000); export type App = typeof app; @@ -11,5 +16,5 @@ export const PUT = app.put; export const DELETE = app.delete; console.log( - `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`, + `🦊 Elysia is running at http://${app.server?.hostname}:${app.server?.port}`, ); diff --git a/apps/server/src/routes/realtime/index.ts b/apps/server/src/routes/realtime/index.ts new file mode 100644 index 0000000..d0802ef --- /dev/null +++ b/apps/server/src/routes/realtime/index.ts @@ -0,0 +1,10 @@ +import Elysia from "elysia"; + +export const realtime = new Elysia().ws("/realtime", { + open: (ws) => { + console.log("WebSocket connection opened"); + }, + message: (ws, message) => { + console.log("Received message:", message); + }, +}); diff --git a/apps/server/src/routes/realtime/types.ts b/apps/server/src/routes/realtime/types.ts new file mode 100644 index 0000000..c3f3733 --- /dev/null +++ b/apps/server/src/routes/realtime/types.ts @@ -0,0 +1,22 @@ +export type Message = { + id: number; + roomId: string; + username: string; + content: string; + timestamp: number; + deleted: boolean; +}; + +// Client -> Server +export type ClientMessage = + | { type: "join"; roomId: string } + | { type: "leave"; roomId: string } + | { type: "message"; roomId: string; m: Message } + | { type: "sync"; roomId: string }; + +// Server -> Client(s) +export type ServerMessage = + | { type: "joined"; username: string } + | { type: "left"; username: string } + | { type: "message"; username: string; m: Message } + | { type: "sync"; roomId: string; messages: Message[] }; diff --git a/bruno/health.yml b/bruno/health.yml new file mode 100644 index 0000000..1fbf56a --- /dev/null +++ b/bruno/health.yml @@ -0,0 +1,21 @@ +info: + name: health + type: http + seq: 1 + +http: + method: GET + url: http://localhost:3000/health + auth: inherit + +runtime: + assertions: + - expression: res.status + operator: eq + value: "200" + +settings: + encodeUrl: true + timeout: 0 + followRedirects: true + maxRedirects: 5 diff --git a/bruno/opencollection.yml b/bruno/opencollection.yml new file mode 100644 index 0000000..2ff597f --- /dev/null +++ b/bruno/opencollection.yml @@ -0,0 +1,10 @@ +opencollection: 1.0.0 + +info: + name: mini-discord +bundled: false +extensions: + bruno: + ignore: + - node_modules + - .git diff --git a/compose.yml b/docker-compose.yml similarity index 67% rename from compose.yml rename to docker-compose.yml index c5b7926..fc10f40 100644 --- a/compose.yml +++ b/docker-compose.yml @@ -15,8 +15,7 @@ services: context: . dockerfile: apps/server/Dockerfile restart: unless-stopped - ports: - - 3000 + # Don't need to expose ports for the server since it's only accessed by the client and not directly by the user environment: - BETTER_AUTH_URL="http://localhost:3000" - DATABASE_URL=postgres://postgres:postgres@postgres:5432/postgres @@ -30,19 +29,15 @@ services: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: postgres - ports: - - "5432:5432" + # Don't need to expose ports for the database since it's only accessed by the server and not directly by the user volumes: - postgres-data:/var/lib/postgresql/data - - redis: - image: redis:7 - restart: always - ports: - - "6379:6379" - volumes: - - redis-data:/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 1m30s + timeout: 30s + retries: 5 + start_period: 30s volumes: postgres-data: - redis-data: