add production stuff
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
PORT=8000
|
||||
NODE_ENV=production
|
||||
DATABASE_URL=file:/app/prisma/dev.db
|
||||
FRONTEND_URL=http://localhost:6767
|
||||
FRONTEND_URL=https://draw.louiscreates.com
|
||||
API_BASE_PATH=/api
|
||||
# Keep disabled unless traffic always comes through a trusted reverse proxy.
|
||||
TRUST_PROXY=false
|
||||
AUTH_MODE=local
|
||||
|
||||
@@ -12,6 +12,7 @@ interface Config {
|
||||
nodeEnv: string;
|
||||
databaseUrl?: string;
|
||||
frontendUrl?: string;
|
||||
apiBasePath: string;
|
||||
authMode: AuthMode;
|
||||
jwtSecret: string;
|
||||
jwtAccessExpiresIn: string;
|
||||
@@ -82,6 +83,22 @@ const parseFrontendUrl = (raw: string | undefined): string | undefined => {
|
||||
return normalized.length > 0 ? normalized : undefined;
|
||||
};
|
||||
|
||||
const parseApiBasePath = (raw: string | undefined): string => {
|
||||
const fallback = "/api";
|
||||
if (!raw || raw.trim().length === 0) return fallback;
|
||||
|
||||
const trimmed = raw.trim();
|
||||
if (trimmed === "/") return "/";
|
||||
|
||||
const withLeadingSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
||||
const withoutTrailingSlash =
|
||||
withLeadingSlash.length > 1 && withLeadingSlash.endsWith("/")
|
||||
? withLeadingSlash.slice(0, -1)
|
||||
: withLeadingSlash;
|
||||
|
||||
return withoutTrailingSlash.length > 0 ? withoutTrailingSlash : fallback;
|
||||
};
|
||||
|
||||
const resolveDatabaseUrl = (rawUrl?: string) => {
|
||||
const backendRoot = path.resolve(__dirname, "../");
|
||||
const defaultDbPath = path.resolve(backendRoot, "prisma/dev.db");
|
||||
@@ -189,6 +206,7 @@ export const config: Config = {
|
||||
nodeEnv: getOptionalEnv("NODE_ENV", "development"),
|
||||
databaseUrl: process.env.DATABASE_URL,
|
||||
frontendUrl: parseFrontendUrl(process.env.FRONTEND_URL),
|
||||
apiBasePath: parseApiBasePath(process.env.API_BASE_PATH),
|
||||
authMode: resolvedAuthMode,
|
||||
jwtSecret: resolveJwtSecret(getOptionalEnv("NODE_ENV", "development")),
|
||||
jwtAccessExpiresIn: getOptionalEnv("JWT_ACCESS_EXPIRES_IN", "15m"),
|
||||
|
||||
+16
-5
@@ -59,6 +59,7 @@ const normalizeOrigins = (rawOrigins?: string | null): string[] => {
|
||||
|
||||
const allowedOrigins = normalizeOrigins(config.frontendUrl);
|
||||
console.log("Allowed origins:", allowedOrigins);
|
||||
console.log("API base path:", config.apiBasePath);
|
||||
|
||||
const isDev = (process.env.NODE_ENV || "development") !== "production";
|
||||
const isLocalDevOrigin = (origin: string): boolean => {
|
||||
@@ -132,6 +133,10 @@ if (trustProxyValue === true) {
|
||||
|
||||
const httpServer = createServer(app);
|
||||
const io = new Server(httpServer, {
|
||||
path:
|
||||
config.apiBasePath === "/"
|
||||
? "/socket.io"
|
||||
: `${config.apiBasePath}/socket.io`,
|
||||
cors: {
|
||||
origin: (origin, cb) => cb(null, isAllowedOrigin(origin ?? undefined)),
|
||||
credentials: true,
|
||||
@@ -329,15 +334,18 @@ const generalRateLimiter = rateLimit({
|
||||
|
||||
app.use(generalRateLimiter);
|
||||
|
||||
const apiApp = express();
|
||||
app.use(config.apiBasePath, apiApp);
|
||||
|
||||
registerCsrfProtection({
|
||||
app,
|
||||
app: apiApp,
|
||||
isAllowedOrigin,
|
||||
maxRequestsPerWindow: config.csrfMaxRequests,
|
||||
enableDebugLogging: process.env.DEBUG_CSRF === "true",
|
||||
});
|
||||
|
||||
// Authentication routes (no CSRF required, uses JWT)
|
||||
app.use("/auth", authRouter);
|
||||
apiApp.use("/auth", authRouter);
|
||||
|
||||
// Files field can contain arbitrary file metadata, so we use unknown and validate structure
|
||||
const filesFieldSchema = z
|
||||
@@ -556,13 +564,13 @@ registerSocketHandlers({
|
||||
jwtSecret: config.jwtSecret,
|
||||
});
|
||||
|
||||
app.get("/health", (req, res) => {
|
||||
apiApp.get("/health", (req, res) => {
|
||||
res.status(200).json({ status: "ok" });
|
||||
});
|
||||
|
||||
// Health check endpoint doesn't require auth
|
||||
|
||||
registerDashboardRoutes(app, {
|
||||
registerDashboardRoutes(apiApp, {
|
||||
prisma,
|
||||
requireAuth,
|
||||
asyncHandler,
|
||||
@@ -584,7 +592,7 @@ registerDashboardRoutes(app, {
|
||||
});
|
||||
|
||||
registerImportExportRoutes({
|
||||
app,
|
||||
app: apiApp,
|
||||
prisma,
|
||||
requireAuth,
|
||||
asyncHandler,
|
||||
@@ -622,5 +630,8 @@ if (isMain) {
|
||||
console.log(`Server running on port ${PORT}`);
|
||||
console.log(`Environment: ${config.nodeEnv}`);
|
||||
console.log(`Frontend URL: ${config.frontendUrl}`);
|
||||
console.log(
|
||||
`API endpoints: ${config.apiBasePath === "/" ? "/" : `${config.apiBasePath}/`}*`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user