File size: 6,944 Bytes
7c012de 999687d 7c012de 951fb3f 7c012de 7127914 7c012de 8a11413 7c012de 0e0c0a2 dd22d79 0e0c0a2 7c012de 0e0c0a2 dd22d79 0e0c0a2 7c012de 7841477 7c012de e57738d 7c012de af2dad0 7c012de |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
console.log("π Starting KnowledgeBridge server...");
// Add global error handlers to catch crashes
process.on('uncaughtException', (error) => {
console.error('π₯ Uncaught Exception:', error);
process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
console.error('π₯ Unhandled Rejection at:', promise, 'reason:', reason);
process.exit(1);
});
import { config } from "dotenv";
import { join, dirname } from "path";
import { fileURLToPath } from "url";
import express, { type Request, Response, NextFunction } from "express";
import rateLimit from "express-rate-limit";
import helmet from "helmet";
import { body, validationResult } from "express-validator";
console.log("β
Basic imports loaded successfully");
import { registerRoutes } from "./routes";
import { setupVite, serveStatic, log } from "./vite";
console.log("β
All imports loaded successfully");
// Get the directory name for ES modules
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Load environment variables from .env file
config({ path: join(__dirname, '../.env') });
const app = express();
// Trust proxy for Hugging Face Spaces infrastructure
if (process.env.NODE_ENV === 'production') {
app.set('trust proxy', true);
}
console.log("β
Express app created");
console.log("β
Server setup starting");
// Security middleware
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: process.env.NODE_ENV === 'production'
? ["'self'", "'unsafe-inline'", "'unsafe-eval'"]
: ["'self'", "'unsafe-inline'", "'unsafe-eval'", "https://replit.com"], // Allow Replit in dev
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
connectSrc: ["'self'", "https://api.studio.nebius.ai", "https://api.github.com"],
frameAncestors: process.env.NODE_ENV === 'production'
? ["'self'", "https://*.hf.space", "https://huggingface.co"]
: ["'self'"], // Allow HF domains in production
},
},
}));
// Rate limiting configuration for production (HF Spaces) vs development
const rateLimitConfig = process.env.NODE_ENV === 'production' ? {
// For HF Spaces - configure for proxy environment
windowMs: 15 * 60 * 1000, // 15 minutes
max: 1000, // Higher limit since we can't reliably identify individual users
message: {
error: "Too many requests, please try again later."
},
standardHeaders: true,
legacyHeaders: false,
// Use a combination of headers for better user identification in proxy environment
keyGenerator: (req) => {
return req.ip + '|' + (req.headers['x-forwarded-for'] || req.headers['cf-connecting-ip'] || req.connection.remoteAddress);
},
// Skip validation that was causing the errors
validate: false,
} : {
// For development - normal rate limiting
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
message: {
error: "Too many requests from this IP, please try again later."
},
standardHeaders: true,
legacyHeaders: false,
};
const limiter = rateLimit(rateLimitConfig);
export const strictLimiter = process.env.NODE_ENV === 'production' ?
rateLimit({
windowMs: 5 * 60 * 1000, // 5 minutes
max: 50, // More generous limit for production
message: {
error: "Too many requests, please try again later."
},
keyGenerator: (req) => {
return req.ip + '|' + (req.headers['x-forwarded-for'] || req.headers['cf-connecting-ip'] || req.connection.remoteAddress);
},
validate: false,
}) :
rateLimit({
windowMs: 1 * 60 * 1000, // 1 minute
max: 10, // limit each IP to 10 requests per minute for sensitive endpoints
message: {
error: "Too many requests, please try again later."
}
});
app.use(limiter);
// Body parsing with size limits
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: false, limit: '10mb' }));
app.use((req, res, next) => {
const start = Date.now();
const path = req.path;
let capturedJsonResponse: Record<string, any> | undefined = undefined;
const originalResJson = res.json;
res.json = function (bodyJson, ...args) {
capturedJsonResponse = bodyJson;
return originalResJson.apply(res, [bodyJson, ...args]);
};
res.on("finish", () => {
const duration = Date.now() - start;
if (path.startsWith("/api")) {
let logLine = `${req.method} ${path} ${res.statusCode} in ${duration}ms`;
if (capturedJsonResponse) {
logLine += ` :: ${JSON.stringify(capturedJsonResponse)}`;
}
if (logLine.length > 80) {
logLine = logLine.slice(0, 79) + "β¦";
}
log(logLine);
}
});
next();
});
(async () => {
const server = await registerRoutes(app);
app.use((err: any, req: Request, res: Response, _next: NextFunction) => {
const status = err.status || err.statusCode || 500;
const message = status === 500 ? "Internal Server Error" : err.message || "Internal Server Error";
console.error(`Error ${status} on ${req.method} ${req.url}:`, err);
// Only send response if not already sent
if (!res.headersSent) {
res.status(status).json({
message,
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
});
}
// Log error but don't throw - throwing here crashes the server
if (status === 500) {
console.error('Internal server error:', err.stack);
}
});
// importantly only setup vite in development and after
// setting up all the other routes so the catch-all route
// doesn't interfere with the other routes
console.log(`Environment: NODE_ENV=${process.env.NODE_ENV}, app.get('env')=${app.get('env')}`);
// Add basic health endpoint before static serving to ensure server is responsive
app.get("/ping", (_req, res) => {
res.json({ status: "ok", timestamp: new Date().toISOString() });
});
if (process.env.NODE_ENV === "development") {
console.log("Setting up Vite development server");
await setupVite(app, server);
} else {
console.log("Setting up static file serving for production");
serveStatic(app);
}
// Seed database with default documents for demo purposes
console.log("π± Initializing database with default documents...");
try {
const { seedDefaultDocuments } = await import('./seed-documents');
await seedDefaultDocuments();
} catch (error) {
console.warn("β οΈ Failed to seed default documents:", error);
}
// Serve the app on the configured port (5000 for local, 7860 for HF Spaces)
// this serves both the API and the client.
const port = process.env.PORT ? parseInt(process.env.PORT) : (process.env.NODE_ENV === 'production' ? 7860 : 5000);
server.listen({
port,
host: "0.0.0.0",
reusePort: true,
}, () => {
log(`serving on port ${port}`);
});
})();
|