From fa6df558f26113f42e4b1d7946d883f761e63b1b Mon Sep 17 00:00:00 2001 From: unownone Date: Thu, 14 Dec 2023 12:56:27 +0530 Subject: [PATCH] fix: resolve #4 build errors --- package.json | 5 +- src/index.ts | 38 +++--- src/server.ts | 332 ++++++++++++++++++++++++++------------------------ tsconfig.json | 7 +- 4 files changed, 195 insertions(+), 187 deletions(-) diff --git a/package.json b/package.json index aa6f10e..3806d52 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ }, "scripts": { "build": "tsc -p tsconfig.json", - "start": "nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/index.ts" + "dev": "nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/index.ts", + "start": "nodemon dist/index.js" } -} +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 91f3546..b03c14e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,26 +10,24 @@ import buildServer from "./server"; * @returns {Promise} A promise that resolves when the server is successfully started */ async function main() { - const server = await buildServer(); - try { - await server.listen({ - port: 8000, - host: "0.0.0.0", - }); - - ["SIGINT", "SIGTERM"].forEach((signal) => { - process.on(signal, async () => { - server.log.info("Shutting down server..."); - await server.close(); - process.exit(0); - }); - }); - - } catch (err) { - server.log.error(err); - process.exit(1); - } + const server = await buildServer(); + try { + await server.listen({ + port: 8000, + host: "0.0.0.0", + }); + ["SIGINT", "SIGTERM"].forEach((signal) => { + process.on(signal, async () => { + server.log.info("Shutting down server..."); + await server.close(); + process.exit(0); + }); + }); + } catch (err) { + server.log.error(err as object); + process.exit(1); + } } -main(); \ No newline at end of file +main(); diff --git a/src/server.ts b/src/server.ts index c85e4c2..98a1367 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,44 +1,45 @@ import Fastify from "fastify"; import initSwagger from "./swagger"; import initRoutes from "./routes"; -import dbConn from 'typeorm-fastify-plugin'; +import dbConn from "typeorm-fastify-plugin"; import PostgresDataSource from "./plugins/db"; import { FastifySSEPlugin } from "fastify-sse-v2"; import { - FastifyReply, - FastifyRequest, - RawRequestDefaultExpression, - RawServerDefault, - RawReplyDefaultExpression, - ContextConfigDefault -} from 'fastify'; -import { RouteGenericInterface } from 'fastify/types/route'; -import { FastifySchema } from 'fastify/types/schema'; -import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'; -import fastifyCron from 'fastify-cron' + FastifyReply, + FastifyRequest, + RawRequestDefaultExpression, + RawServerDefault, + RawReplyDefaultExpression, + ContextConfigDefault, +} from "fastify"; +import { RouteGenericInterface } from "fastify/types/route"; +import { FastifySchema } from "fastify/types/schema"; +import { TypeBoxTypeProvider } from "@fastify/type-provider-typebox"; +import fastifyCron from "fastify-cron"; import { HEALTH_CHECK_CRON_JOB_EXPRESSION } from "./constants"; import initData from "./scripts"; import * as Sentry from "@sentry/node"; import { User } from "./models/User"; -export type FastifyRequestTypebox = FastifyRequest< +export type FastifyRequestTypebox = + FastifyRequest< RouteGenericInterface, RawServerDefault, RawRequestDefaultExpression, TSchema, TypeBoxTypeProvider ->; + >; export type FastifyReplyTypebox = FastifyReply< - RawServerDefault, - RawRequestDefaultExpression, - RawReplyDefaultExpression, - RouteGenericInterface, - ContextConfigDefault, - TSchema, - TypeBoxTypeProvider -> + RawServerDefault, + RawRequestDefaultExpression, + RawReplyDefaultExpression, + RouteGenericInterface, + ContextConfigDefault, + TSchema, + TypeBoxTypeProvider +>; /** * Initializes and configures the Fastify server, including database connection, @@ -47,149 +48,156 @@ export type FastifyReplyTypebox = FastifyReply< * @returns {Promise} A promise that resolves to the configured Fastify server instance. */ async function buildServer() { - - // Create a new Fastify server instance with pretty print logging enabled. - const server = Fastify({ - logger: { - transport: { - target: "pino-pretty", - }, - }, - }).withTypeProvider(); - + // Create a new Fastify server instance with pretty print logging enabled. + const server = Fastify({ + logger: { + transport: { + target: "pino-pretty", + }, + }, + }).withTypeProvider(); + + try { + // Connect to the database using the TypeORM plugin. + await server.register(dbConn, { connection: PostgresDataSource }); + } catch (err) { + // Log and exit if the database connection fails. + server.log.error("Error connecting to database"); + server.log.error(err as object); + process.exit(1); + } + + // server.setErrorHandler(async (error, request, reply) => { + // console.log('Error: ', error); + // Sentry.captureException(error); + // reply.status(500).send({ error: error.message || "Something went wrong" }); + // }); + // Register JWT support for authentication. + server.register(require("@fastify/jwt"), { + secret: process.env.JWT_SECRET, + sign: { + expiresIn: "14d", + }, + }); + + // Register the authentication decorator for the server. + server.decorate("authenticate", async (request: any, reply: any) => { try { - // Connect to the database using the TypeORM plugin. - await server.register(dbConn, { connection: PostgresDataSource }); + const secret = request.headers["ws-secret"]; + if (!secret) { + await request.jwtVerify(); + return; + } + + if (secret === process.env.WS_SECRET) { + return; + } + + const orm = request.server.orm; + const user = await orm + .getRepository(User) + .findOne({ where: { apikey: secret } }); + if (user) { + request.user = user; + return; + } + + reply.code(401).send({ message: "Unauthorized" }); } catch (err) { - // Log and exit if the database connection fails. - server.log.error("Error connecting to database"); - server.log.error(err); - process.exit(1); + reply.code(401).send({ message: "Unauthorized" }); } + }); + + // Register the Server-Sent Events (SSE) plugin. + server.register(FastifySSEPlugin); + + // Register CORS handling. + server.register(require("@fastify/cors"), (instance) => { + return (req: any, callback: any) => { + const corsOptions = { + // This is NOT recommended for production as it enables reflection exploits + origin: true, + }; + + // TODO: Add a whitelist of allowed origins + + // do not include CORS headers for requests from localhost + if (/^localhost$/m.test(req.headers.origin)) { + corsOptions.origin = false; + } + + // callback expects two parameters: error and options + callback(null, corsOptions); + }; + }); + + server.register(fastifyCron, { + jobs: [ + { + cronTime: HEALTH_CHECK_CRON_JOB_EXPRESSION, + onTick: async (server) => { + try { + // @ts-ignore + const token = server.jwt.sign({}); + const response = await server.inject({ + url: "api/v1/healthcheck", + method: "POST", + headers: { Authorization: `Bearer ${token}` }, + }); + } catch (err) { + console.log(err); + Sentry.captureException(err); + } + }, + start: true, + }, + ], + }); + + Sentry.init({ + dsn: process.env.SENTRY_DSN, + tracesSampleRate: 1.0, + }); + + // Set a custom error handler for the server that sends errors to Sentry. + server.setErrorHandler(async (error, request, reply) => { + console.log("Error: ", error); + if (error.statusCode === 429) { + return reply + .code(429) + .send({ message: "You've reached a limit on preview generations" }); + } + Sentry.captureException(error); + reply.status(500).send({ error: "Something went wrong" }); + }); + + // Register a default root route. + server.get("/", async function (request, reply) { + reply.code(200).send({ hello: "Writesonic's model router" }); + }); + + // Register a health check route. + server.get("/healthcheck", async function (request, reply) { + reply.code(200).send({ status: "ok" }); + }); + + // Initialize Swagger documentation plugin and define the API structure. + await initSwagger(server); + + // Initialize all routes within the application. + initRoutes(server); + + // Run any initialization scripts needed for the application. + await initData(server.orm); + + // Signals that server is ready to accept requests. + await server.ready(); + + // Serve Swagger-generated API documentation. + // @ts-ignore + server.swagger(); - // server.setErrorHandler(async (error, request, reply) => { - // console.log('Error: ', error); - // Sentry.captureException(error); - // reply.status(500).send({ error: error.message || "Something went wrong" }); - // }); - // Register JWT support for authentication. - server.register(require('@fastify/jwt'), { - secret: process.env.JWT_SECRET, - sign: { - expiresIn: '14d' - } - }); - - // Register the authentication decorator for the server. - server.decorate("authenticate", async (request, reply) => { - try { - const secret = request.headers['ws-secret']; - if (!secret) { - await request.jwtVerify(); - return; - } - - if (secret === process.env.WS_SECRET) { - return; - } - - const orm = request.server.orm; - const user = await orm.getRepository(User).findOne({ where: { apikey: secret } }); - if (user) { - request.user = user; - return; - } - - reply.code(401).send({ message: "Unauthorized" }); - } catch (err) { - reply.code(401).send({ message: "Unauthorized" }); - } - }); - - // Register the Server-Sent Events (SSE) plugin. - server.register(FastifySSEPlugin); - - // Register CORS handling. - server.register(require('@fastify/cors'), (instance) => { - return (req: any, callback: any) => { - const corsOptions = { - // This is NOT recommended for production as it enables reflection exploits - origin: true - }; - - // TODO: Add a whitelist of allowed origins - - // do not include CORS headers for requests from localhost - if (/^localhost$/m.test(req.headers.origin)) { - corsOptions.origin = false - } - - // callback expects two parameters: error and options - callback(null, corsOptions) - } - }) - - server.register(fastifyCron, { - jobs: [ - { - cronTime: HEALTH_CHECK_CRON_JOB_EXPRESSION, - onTick: async server => { - try { - // @ts-ignore - const token = server.jwt.sign({}) - const response = await server.inject({ url: 'api/v1/healthcheck', method: 'POST', headers: { Authorization: `Bearer ${token}` } }) - } catch (err) { - console.log(err) - Sentry.captureException(err); - } - }, - start: true - } - ] - }) - - Sentry.init({ - dsn: process.env.SENTRY_DSN, - tracesSampleRate: 1.0, - }); - - // Set a custom error handler for the server that sends errors to Sentry. - server.setErrorHandler(async (error, request, reply) => { - console.log('Error: ', error); - if (error.statusCode === 429) { - return reply.code(429).send({ message: "You've reached a limit on preview generations" }); - } - Sentry.captureException(error); - reply.status(500).send({ error: "Something went wrong" }); - }); - - // Register a default root route. - server.get("/", async function (request: any, reply: any) { - reply.code(200).send({ hello: "Writesonic's model router" }); - }); - - // Register a health check route. - server.get("/healthcheck", async function (request: any, reply: any) { - reply.code(200).send({ status: "ok" }); - }); - - // Initialize Swagger documentation plugin and define the API structure. - await initSwagger(server); - - // Initialize all routes within the application. - initRoutes(server); - - // Run any initialization scripts needed for the application. - await initData(server.orm); - - // Signals that server is ready to accept requests. - await server.ready() - - // Serve Swagger-generated API documentation. - // @ts-ignore - server.swagger() - - return server; + return server; } -export default buildServer; \ No newline at end of file +export default buildServer; diff --git a/tsconfig.json b/tsconfig.json index f9762ce..9f2cee9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,22 +6,23 @@ "module": "commonjs", "rootDir": "./src", "moduleResolution": "node", - "typeRoots": [ "./@types", "./node_modules/@types", ], - "esModuleInterop": true, "forceConsistentCasingInFileNames": false, "strict": true, "strictPropertyInitialization": false, "skipLibCheck": true, + "outDir": "./dist", }, "typedocOptions": { "entryPointStrategy": "expand", "out": "./docs/docs/03-code", // "externalPattern": "**/node_modules/**", }, - "exclude": ["docs"] + "exclude": [ + "docs" + ] } \ No newline at end of file