diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml index 7234009..8b4f7d1 100644 --- a/.github/workflows/container.yml +++ b/.github/workflows/container.yml @@ -28,7 +28,7 @@ jobs: steps: - name: 'Checkout' - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: 'Setup tags' id: setup-tags diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..97a4932 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "cSpell.words": [ + "autoroutes", + "elysia", + "elysiajs" + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 06d3e0f..d7813f7 100644 Binary files a/README.md and b/README.md differ diff --git a/bun.lockb b/bun.lockb index 5474b3a..cced51b 100644 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index d2a463f..ccaaac8 100644 --- a/package.json +++ b/package.json @@ -1,30 +1,31 @@ { - "name": "@tnfangel-chat/api", - "version": "1.0.0", - "description": "tnfAngel Chat API Service", - "type": "module", - "private": true, - "scripts": { - "build": "bun run build:bundle", - "build:bundle": "bun build --target bun --format esm --minify --outdir ./dist/ ./src/index.ts", - "build:standalone": "bun build --compile --target bun --format esm --minify --outfile ./dist/aurora ./src/index.ts", - "start": "bun run build && bun ./dist/index.js", - "dev": "NODE_ENV=development bun --hot src/index.ts", - "production:build": "bun run build:standalone", - "lint": "bunx --bun @biomejs/biome check --apply ." - }, - "author": "tnfAngel", - "dependencies": { - "@elysiajs/cors": "^1.0.2", - "elysia": "^1.0.21", - "tslib": "^2.6.2" - }, - "devDependencies": { - "@biomejs/biome": "^1.7.3", - "@types/bun": "^1.1.3", - "typescript": "5.4.5" - }, - "peerDependencies": { - "typescript": "^5.0.0" - } + "name": "@tnfangel-chat/api", + "version": "1.0.0", + "description": "tnfAngel Chat API Service", + "type": "module", + "private": true, + "scripts": { + "build": "bun run build:bundle", + "build:bundle": "bun build --target bun --format esm --minify --outdir ./dist/ ./src/index.ts", + "build:standalone": "bun build --compile --target bun --format esm --minify --outfile ./dist/aurora ./src/index.ts", + "start": "bun run build && bun ./dist/index.js", + "dev": "NODE_ENV=development bun --hot src/index.ts", + "production:build": "bun run build:standalone", + "lint": "bunx --bun @biomejs/biome check --apply ." + }, + "author": "tnfAngel", + "dependencies": { + "@elysiajs/cors": "^1.0.2", + "elysia": "^1.0.21", + "elysia-autoroutes": "^0.5.0", + "tslib": "^2.6.2" + }, + "devDependencies": { + "@biomejs/biome": "^1.7.3", + "@types/bun": "^1.1.3", + "typescript": "5.4.5" + }, + "peerDependencies": { + "typescript": "^5.0.0" + } } diff --git a/src/classes/Server.ts b/src/classes/Server.ts new file mode 100644 index 0000000..c9a0485 --- /dev/null +++ b/src/classes/Server.ts @@ -0,0 +1,55 @@ +import cors from '@elysiajs/cors'; +import { Elysia } from 'elysia'; +import { autoroutes } from 'elysia-autoroutes'; + +export class Server { + public static readonly port = process.env['PORT'] ?? 4000; + + public elysia: Elysia = new Elysia({ precompile: true }); + + public constructor() { + this.initCORS(); + this.initErrorListener(); + this.initRoutes(); + } + + private initCORS(): void { + this.elysia.use(cors()); + } + + private initErrorListener(): void { + this.elysia.onError(({ code, error }) => { + if (code === 'NOT_FOUND') { + return 'Not Found'; + } + + if (code === 'VALIDATION') { + return 'Validation Error'; + } + + if (code === 'PARSE') { + return 'Parse Error'; + } + + if (error instanceof Error || code === 'INTERNAL_SERVER_ERROR') { + console.error(error); + return 'Internal Server Error'; + } + + return error; + }); + } + + private initRoutes(): void { + this.elysia.use( + autoroutes({ + routesDir: './routes', // -> optional, defaults to './routes' + generateTags: false // -> optional, defaults to true + }) + ); + } + + public listen() { + this.elysia.listen(Server.port, ({ port }) => console.info(`Listening on: http://localhost:${port}`)); + } +} diff --git a/src/index.ts b/src/index.ts index 7bc4a71..0f4a969 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1,7 @@ -console.log('Hello world'); +import { Server } from './classes/Server.ts'; + +const sv = new Server(); + +sv.listen(); + +export type ElysiaApp = typeof sv.elysia; diff --git a/src/routes/channels/[channelId]/messages.ts b/src/routes/channels/[channelId]/messages.ts new file mode 100644 index 0000000..f7e4249 --- /dev/null +++ b/src/routes/channels/[channelId]/messages.ts @@ -0,0 +1,25 @@ +import { t } from 'elysia'; +import type { ElysiaApp } from '../../..'; + +export default (app: ElysiaApp) => + app.post( + '/', + async ({ body, params }) => { + console.log(body, params); + }, + { + params: t.Object({ + channelId: t.Numeric({ + description: 'The channel id', + examples: ['123'] + }) + }), + body: t.Object({ + content: t.String({ description: 'The message content', minLength: 1, maxLength: 2000 }), + nonce: t.String({ description: 'Message internal identifier', minLength: 1, maxLength: 255 }) + }), + response: { + 200: t.Void() + } + } + );