Initialize project scaffold with full web and API setup.
Add the Vite frontend, Express API server, and supporting configuration files so the app can run locally on a complete development stack. Made-with: Cursor
This commit is contained in:
78
server/index.ts
Normal file
78
server/index.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Local API for MySQL. Keeps credentials off the client.
|
||||
* Run: npm run server, or npm run dev (starts API + Vite together).
|
||||
*/
|
||||
import "dotenv/config";
|
||||
import cors from "cors";
|
||||
import express from "express";
|
||||
import path from "path";
|
||||
import type { RowDataPacket } from "mysql2";
|
||||
import mysql from "mysql2/promise";
|
||||
import { registerAuthRoutes } from "./auth";
|
||||
import { registerCourseVideoRoutes } from "./courseVideos";
|
||||
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
app.use(
|
||||
cors({
|
||||
origin: process.env.CORS_ORIGIN?.split(",").map((s) => s.trim()) ?? true,
|
||||
}),
|
||||
);
|
||||
|
||||
const apiPort = Number(process.env.API_PORT ?? 3001);
|
||||
const apiHost = process.env.API_HOST ?? "127.0.0.1";
|
||||
|
||||
function sslOption(): boolean | { rejectUnauthorized: boolean } | undefined {
|
||||
if (process.env.MYSQL_SSL !== "true") return undefined;
|
||||
if (process.env.MYSQL_SSL_INSECURE === "true") {
|
||||
return { rejectUnauthorized: false };
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
let pool: mysql.Pool | null = null;
|
||||
|
||||
function getPool(): mysql.Pool {
|
||||
if (pool) return pool;
|
||||
const host = process.env.MYSQL_HOST || process.env.DB_HOST;
|
||||
const user = process.env.MYSQL_USER || process.env.DB_USER;
|
||||
const database = process.env.MYSQL_DATABASE || process.env.DB_NAME;
|
||||
if (!host || !user || !database) {
|
||||
throw new Error("Set DB_HOST, DB_USER, DB_NAME (or MYSQL_*) in .env");
|
||||
}
|
||||
const portEnv = process.env.MYSQL_PORT || process.env.DB_PORT;
|
||||
pool = mysql.createPool({
|
||||
host,
|
||||
port: Number(portEnv ?? 3306),
|
||||
user,
|
||||
password: process.env.MYSQL_PASSWORD ?? process.env.DB_PASSWORD ?? "",
|
||||
database,
|
||||
waitForConnections: true,
|
||||
connectionLimit: Number(process.env.MYSQL_CONNECTION_LIMIT ?? 5),
|
||||
ssl: sslOption(),
|
||||
});
|
||||
return pool;
|
||||
}
|
||||
|
||||
registerAuthRoutes(app, getPool);
|
||||
registerCourseVideoRoutes(app, getPool);
|
||||
|
||||
app.use("/uploads", express.static(path.join(process.cwd(), "uploads")));
|
||||
|
||||
app.get("/api/health", (_req, res) => {
|
||||
res.json({ ok: true });
|
||||
});
|
||||
|
||||
app.get("/api/db/ping", async (_req, res) => {
|
||||
try {
|
||||
const [rows] = await getPool().query<RowDataPacket[]>("SELECT 1 AS ok");
|
||||
res.json({ ok: true, rows });
|
||||
} catch (err) {
|
||||
console.error("[db/ping]", err);
|
||||
res.status(503).json({ ok: false, error: "Database unreachable" });
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(apiPort, apiHost, () => {
|
||||
console.log(`API listening on http://${apiHost}:${apiPort}`);
|
||||
});
|
||||
Reference in New Issue
Block a user