|
console.log("π Starting KnowledgeBridge server..."); |
|
|
|
|
|
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"); |
|
|
|
|
|
const __filename = fileURLToPath(import.meta.url); |
|
const __dirname = dirname(__filename); |
|
|
|
|
|
config({ path: join(__dirname, '../.env') }); |
|
|
|
const app = express(); |
|
|
|
|
|
if (process.env.NODE_ENV === 'production') { |
|
app.set('trust proxy', true); |
|
} |
|
|
|
console.log("β
Express app created"); |
|
|
|
console.log("β
Server setup starting"); |
|
|
|
|
|
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"], |
|
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'"], |
|
}, |
|
}, |
|
})); |
|
|
|
|
|
const rateLimitConfig = process.env.NODE_ENV === 'production' ? { |
|
|
|
windowMs: 15 * 60 * 1000, |
|
max: 1000, |
|
message: { |
|
error: "Too many requests, please try again later." |
|
}, |
|
standardHeaders: true, |
|
legacyHeaders: false, |
|
|
|
keyGenerator: (req) => { |
|
return req.ip + '|' + (req.headers['x-forwarded-for'] || req.headers['cf-connecting-ip'] || req.connection.remoteAddress); |
|
}, |
|
|
|
validate: false, |
|
} : { |
|
|
|
windowMs: 15 * 60 * 1000, |
|
max: 100, |
|
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, |
|
max: 50, |
|
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, |
|
max: 10, |
|
message: { |
|
error: "Too many requests, please try again later." |
|
} |
|
}); |
|
|
|
app.use(limiter); |
|
|
|
|
|
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); |
|
|
|
|
|
if (!res.headersSent) { |
|
res.status(status).json({ |
|
message, |
|
...(process.env.NODE_ENV === 'development' && { stack: err.stack }) |
|
}); |
|
} |
|
|
|
|
|
if (status === 500) { |
|
console.error('Internal server error:', err.stack); |
|
} |
|
}); |
|
|
|
|
|
|
|
|
|
console.log(`Environment: NODE_ENV=${process.env.NODE_ENV}, app.get('env')=${app.get('env')}`); |
|
|
|
|
|
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); |
|
} |
|
|
|
|
|
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); |
|
} |
|
|
|
|
|
|
|
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}`); |
|
}); |
|
})(); |
|
|