2025-10-18 22:16:04 -07:00
|
|
|
import compression from "compression";
|
2025-10-18 22:20:06 -07:00
|
|
|
import express from "express";
|
|
|
|
|
import type { Express, Request, Response, NextFunction } from "express";
|
2025-10-18 22:16:04 -07:00
|
|
|
import morgan from "morgan";
|
|
|
|
|
import { createServer } from "http";
|
|
|
|
|
import type { ViteDevServer } from "vite";
|
|
|
|
|
import path from "path";
|
|
|
|
|
import { fileURLToPath } from "url";
|
2026-03-07 22:31:04 -08:00
|
|
|
import { drizzle } from "drizzle-orm/postgres-js";
|
|
|
|
|
import { migrate } from "drizzle-orm/postgres-js/migrator";
|
|
|
|
|
import postgres from "postgres";
|
2026-03-21 13:41:39 -07:00
|
|
|
import { logger } from "./server/logger";
|
2025-10-18 22:16:04 -07:00
|
|
|
|
|
|
|
|
// ESM module resolution helpers
|
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
|
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
|
|
|
|
|
|
// Configuration
|
|
|
|
|
// Resolve paths relative to project root (one level up from dist/ in production, or current dir in dev)
|
|
|
|
|
const PROJECT_ROOT = path.resolve(__dirname, "..");
|
|
|
|
|
const BUILD_PATH = path.join(PROJECT_ROOT, "build/server/index.js");
|
|
|
|
|
const CLIENT_BUILD_PATH = path.join(PROJECT_ROOT, "build/client");
|
|
|
|
|
const CLIENT_ASSETS_PATH = path.join(PROJECT_ROOT, "build/client/assets");
|
|
|
|
|
const DEVELOPMENT = process.env.NODE_ENV === "development";
|
|
|
|
|
const PORT = Number.parseInt(process.env.PORT || "3000", 10);
|
|
|
|
|
|
2026-03-07 22:31:04 -08:00
|
|
|
async function runMigrations(): Promise<void> {
|
|
|
|
|
if (!process.env.DATABASE_URL) {
|
|
|
|
|
throw new Error("DATABASE_URL is required");
|
|
|
|
|
}
|
|
|
|
|
const client = postgres(process.env.DATABASE_URL);
|
|
|
|
|
try {
|
|
|
|
|
const db = drizzle(client);
|
|
|
|
|
await migrate(db, { migrationsFolder: path.join(PROJECT_ROOT, "drizzle") });
|
2026-03-21 13:41:39 -07:00
|
|
|
logger.log("Migrations complete");
|
2026-03-07 22:31:04 -08:00
|
|
|
} finally {
|
|
|
|
|
await client.end();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-18 22:16:04 -07:00
|
|
|
async function createAppServer(): Promise<void> {
|
|
|
|
|
const app: Express = express();
|
|
|
|
|
|
|
|
|
|
app.use(compression());
|
|
|
|
|
app.disable("x-powered-by");
|
|
|
|
|
|
|
|
|
|
if (DEVELOPMENT) {
|
2026-03-21 13:41:39 -07:00
|
|
|
logger.log("Starting development server");
|
2025-10-18 22:16:04 -07:00
|
|
|
|
|
|
|
|
// Dynamic import Vite only in development
|
|
|
|
|
const { createServer: createViteServer } = await import("vite");
|
|
|
|
|
|
|
|
|
|
const viteDevServer: ViteDevServer = await createViteServer({
|
|
|
|
|
server: { middlewareMode: true },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
app.use(viteDevServer.middlewares);
|
|
|
|
|
|
|
|
|
|
app.use(async (req: Request, res: Response, next: NextFunction) => {
|
|
|
|
|
try {
|
|
|
|
|
const source = await viteDevServer.ssrLoadModule("./server/app.ts");
|
|
|
|
|
return await source.app(req, res, next);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
if (error instanceof Error) {
|
|
|
|
|
viteDevServer.ssrFixStacktrace(error);
|
|
|
|
|
}
|
|
|
|
|
next(error);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} else {
|
2026-03-21 13:41:39 -07:00
|
|
|
logger.log("Starting production server");
|
2025-10-18 22:16:04 -07:00
|
|
|
|
|
|
|
|
app.use(
|
|
|
|
|
"/assets",
|
|
|
|
|
express.static(CLIENT_ASSETS_PATH, {
|
|
|
|
|
immutable: true,
|
|
|
|
|
maxAge: "1y"
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
app.use(morgan("tiny"));
|
|
|
|
|
app.use(express.static(CLIENT_BUILD_PATH, { maxAge: "1h" }));
|
|
|
|
|
|
|
|
|
|
// Import the built React Router app
|
|
|
|
|
const { app: productionApp } = await import(BUILD_PATH);
|
|
|
|
|
app.use(productionApp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create HTTP server
|
|
|
|
|
const httpServer = createServer(app);
|
|
|
|
|
|
|
|
|
|
// Initialize Socket.IO
|
|
|
|
|
const { initializeSocketIO } = await import("./server/socket");
|
|
|
|
|
initializeSocketIO(httpServer);
|
|
|
|
|
|
|
|
|
|
// Start server
|
|
|
|
|
httpServer.listen(PORT, () => {
|
2026-03-21 13:41:39 -07:00
|
|
|
logger.log(`Server is running on http://localhost:${PORT}`);
|
2025-10-18 22:16:04 -07:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Start the server with error handling
|
2026-03-07 22:31:04 -08:00
|
|
|
(DEVELOPMENT ? Promise.resolve() : runMigrations())
|
|
|
|
|
.then(createAppServer)
|
|
|
|
|
.catch((error) => {
|
2026-03-21 13:41:39 -07:00
|
|
|
logger.error("Failed to start server:", error);
|
2026-03-07 22:31:04 -08:00
|
|
|
process.exit(1);
|
|
|
|
|
});
|