the statusphere demo reworked into a vite/react app in a monorepo
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 { Database } from "#/db";
13import { Firehose } from "#/firehose";
14import { addRoutes } from "#/routes";
15
16export class Server {
17 constructor(
18 public app: express.Application,
19 public server: http.Server,
20 public firehose: Firehose,
21 public logger: pino.Logger,
22 ) {}
23
24 static async create() {
25 const { NODE_ENV, HOST, PORT } = env;
26
27 await Database.sync({ force: true });
28
29 const logger = pino({ name: "server start" });
30 const app: Express = express();
31
32 // Set the application to trust the reverse proxy
33 app.set("trust proxy", true);
34
35 // TODO: middleware for sqlite server
36 // TODO: middleware for OAuth
37
38 // Middlewares
39 app.use(express.json());
40 app.use(express.urlencoded({ extended: true }));
41 app.use(cors({ origin: env.CORS_ORIGIN, credentials: true }));
42 app.use(helmet());
43 app.use(rateLimiter);
44
45 // Request logging
46 app.use(requestLogger);
47
48 addRoutes(app);
49
50 // Error handlers
51 app.use(errorHandler());
52
53 const server = app.listen(env.PORT);
54 await events.once(server, "listening");
55 logger.info(`Server (${NODE_ENV}) running on port http://${HOST}:${PORT}`);
56
57 const firehose = new Firehose("https://bsky.network");
58 firehose.run(10);
59
60 return new Server(app, server, firehose, logger);
61 }
62
63 async close() {
64 this.logger.info("sigint received, shutting down");
65 return new Promise<void>((resolve) => {
66 this.server.close(() => {
67 this.logger.info("server closed");
68 resolve();
69 });
70 });
71 }
72}