mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-13 08:26:40 +00:00
bootstrapped
This commit is contained in:
9
server/db/index.ts
Normal file
9
server/db/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { drizzle } from "drizzle-orm/better-sqlite3";
|
||||
import Database from "better-sqlite3";
|
||||
import * as schema from "./schema";
|
||||
import environment from "@server/environment";
|
||||
|
||||
const sqlite = new Database(`${environment.CONFIG_PATH}/db/db.sqlite`);
|
||||
export const db = drizzle(sqlite, { schema });
|
||||
|
||||
export default db;
|
||||
10
server/db/schema.ts
Normal file
10
server/db/schema.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { InferSelectModel } from "drizzle-orm";
|
||||
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
||||
|
||||
export const schools = sqliteTable("schools", {
|
||||
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||
name: text("name"),
|
||||
abbreviation: text("abbreviation"),
|
||||
});
|
||||
|
||||
export type SelectSchoolType = InferSelectModel<typeof schools>;
|
||||
27
server/environment.ts
Normal file
27
server/environment.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { z } from "zod";
|
||||
import { fromError } from "zod-validation-error";
|
||||
|
||||
const environmentSchema = z.object({
|
||||
ENVIRONMENT: z.string(),
|
||||
LOG_LEVEL: z.string(),
|
||||
SAVE_LOGS: z.string().transform((val) => val === "true"),
|
||||
PORT: z.string(),
|
||||
CONFIG_PATH: z.string(),
|
||||
});
|
||||
|
||||
const environment = {
|
||||
ENVIRONMENT: (process.env.ENVIRONMENT as string) || "dev",
|
||||
LOG_LEVEL: (process.env.LOG_LEVEL as string) || "debug",
|
||||
SAVE_LOGS: (process.env.SAVE_LOGS as string) || "false",
|
||||
PORT: (process.env.PORT as string) || "3000",
|
||||
CONFIG_PATH: process.env.CONFIG_PATH as string,
|
||||
};
|
||||
|
||||
const parsedConfig = environmentSchema.safeParse(environment);
|
||||
|
||||
if (!parsedConfig.success) {
|
||||
const errors = fromError(parsedConfig.error);
|
||||
throw new Error(`Invalid environment configuration: ${errors}`);
|
||||
}
|
||||
|
||||
export default parsedConfig.data;
|
||||
36
server/index.ts
Normal file
36
server/index.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import express, { Request, Response } from "express";
|
||||
import next from "next";
|
||||
import { parse } from "url";
|
||||
import environment from "./environment";
|
||||
import logger from "@/server/logger";
|
||||
import helmet from "helmet";
|
||||
import cors from "cors";
|
||||
import unauth from "@server/routers/unauth";
|
||||
|
||||
const dev = environment.ENVIRONMENT !== "prod";
|
||||
const app = next({ dev });
|
||||
const handle = app.getRequestHandler();
|
||||
|
||||
const port = environment.PORT;
|
||||
|
||||
app.prepare().then(() => {
|
||||
const server = express();
|
||||
|
||||
server.use(helmet());
|
||||
server.use(cors());
|
||||
|
||||
const prefix = `/api`;
|
||||
server.use(prefix, express.json(), unauth);
|
||||
|
||||
server.all("*", (req: Request, res: Response) => {
|
||||
const parsedUrl = parse(req.url!, true);
|
||||
handle(req, res, parsedUrl);
|
||||
});
|
||||
|
||||
server.listen(port, (err?: any) => {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
logger.info(`Server is running on http://localhost:${port}`);
|
||||
});
|
||||
});
|
||||
67
server/logger.ts
Normal file
67
server/logger.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import "winston-daily-rotate-file";
|
||||
|
||||
import environment from "@server/environment";
|
||||
import * as winston from "winston";
|
||||
|
||||
const hformat = winston.format.printf(
|
||||
({ level, label, message, timestamp, ...metadata }) => {
|
||||
let msg = `${timestamp} [${level}]${label ? `[${label}]` : ""}: ${message} `;
|
||||
if (Object.keys(metadata).length > 0) {
|
||||
msg += JSON.stringify(metadata);
|
||||
}
|
||||
return msg;
|
||||
},
|
||||
);
|
||||
|
||||
const transports: any = [
|
||||
new winston.transports.Console({
|
||||
format: winston.format.combine(
|
||||
winston.format.colorize(),
|
||||
winston.format.splat(),
|
||||
winston.format.timestamp(),
|
||||
hformat,
|
||||
),
|
||||
}),
|
||||
];
|
||||
|
||||
if (environment.SAVE_LOGS) {
|
||||
transports.push(
|
||||
new winston.transports.DailyRotateFile({
|
||||
filename: `${environment.CONFIG_PATH}/logs/pangolin-%DATE%.log`,
|
||||
datePattern: "YYYY-MM-DD",
|
||||
zippedArchive: true,
|
||||
maxSize: "20m",
|
||||
maxFiles: "7d",
|
||||
createSymlink: true,
|
||||
symlinkName: "pangolin.log",
|
||||
}),
|
||||
);
|
||||
transports.push(
|
||||
new winston.transports.DailyRotateFile({
|
||||
filename: `${environment.CONFIG_PATH}/logs/.machinelogs-%DATE%.json`,
|
||||
datePattern: "YYYY-MM-DD",
|
||||
zippedArchive: true,
|
||||
maxSize: "20m",
|
||||
maxFiles: "1d",
|
||||
createSymlink: true,
|
||||
symlinkName: ".machinelogs.json",
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp(),
|
||||
winston.format.splat(),
|
||||
winston.format.json(),
|
||||
),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const logger = winston.createLogger({
|
||||
level: environment.LOG_LEVEL.toLowerCase(),
|
||||
format: winston.format.combine(
|
||||
winston.format.splat(),
|
||||
winston.format.timestamp(),
|
||||
hformat,
|
||||
),
|
||||
transports,
|
||||
});
|
||||
|
||||
export default logger;
|
||||
9
server/routers/unauth.ts
Normal file
9
server/routers/unauth.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Router } from "express";
|
||||
|
||||
const unauth = Router();
|
||||
|
||||
unauth.get("/", (_, res) => {
|
||||
res.status(200).json({ message: "Healthy" });
|
||||
});
|
||||
|
||||
export default unauth;
|
||||
Reference in New Issue
Block a user