Scratch space for learning atproto app development
1import events from "node:events"; 2import type http from "node:http"; 3import cors from "cors"; 4import express, { type Express } from "express"; 5import helmet from "helmet"; 6import { pino } from "pino"; 7 8import errorHandler from "#/common/middleware/errorHandler"; 9import rateLimiter from "#/common/middleware/rateLimiter"; 10import requestLogger from "#/common/middleware/requestLogger"; 11import { env } from "#/common/utils/envConfig"; 12import { createDb, migrateToLatest } from "#/db"; 13import { Firehose } from "#/firehose"; 14import { createRouter } from "#/router"; 15import type { AppContext } from "./config"; 16 17export class Server { 18 constructor( 19 public app: express.Application, 20 public server: http.Server, 21 public ctx: AppContext 22 ) {} 23 24 static async create() { 25 const { NODE_ENV, HOST, PORT } = env; 26 27 const logger = pino({ name: "server start" }); 28 const db = createDb(":memory:"); 29 await migrateToLatest(db); 30 const firehose = new Firehose("https://bsky.network", db); 31 firehose.run(10); 32 const ctx = { 33 db, 34 firehose, 35 logger, 36 }; 37 38 const app: Express = express(); 39 40 // Set the application to trust the reverse proxy 41 app.set("trust proxy", true); 42 43 // TODO: middleware for sqlite server 44 // TODO: middleware for OAuth 45 46 // Middlewares 47 app.use(express.json()); 48 app.use(express.urlencoded({ extended: true })); 49 app.use(cors({ origin: env.CORS_ORIGIN, credentials: true })); 50 app.use(helmet()); 51 app.use(rateLimiter); 52 53 // Request logging 54 app.use(requestLogger); 55 56 // Routes 57 const router = createRouter(ctx); 58 app.use(router); 59 60 // Error handlers 61 app.use(errorHandler()); 62 63 const server = app.listen(env.PORT); 64 await events.once(server, "listening"); 65 logger.info(`Server (${NODE_ENV}) running on port http://${HOST}:${PORT}`); 66 67 return new Server(app, server, ctx); 68 } 69 70 async close() { 71 this.ctx.logger.info("sigint received, shutting down"); 72 return new Promise<void>((resolve) => { 73 this.server.close(() => { 74 this.ctx.logger.info("server closed"); 75 resolve(); 76 }); 77 }); 78 } 79}