2024-12-30 15:48:34 -05:00
import express from "express" ;
2024-12-07 22:07:13 -05:00
import cors from "cors" ;
import cookieParser from "cookie-parser" ;
2025-01-01 21:41:31 -05:00
import config from "@server/lib/config" ;
2024-12-07 22:07:13 -05:00
import logger from "@server/logger" ;
2024-12-12 22:46:58 -05:00
import {
errorHandlerMiddleware ,
2025-07-14 22:21:04 -07:00
notFoundMiddleware
2024-12-12 22:46:58 -05:00
} from "@server/middlewares" ;
2024-12-07 22:07:13 -05:00
import { authenticated , unauthenticated } from "@server/routers/external" ;
import { router as wsRouter , handleWSUpgrade } from "@server/routers/ws" ;
import { logIncomingMiddleware } from "./middlewares/logIncoming" ;
2024-12-25 22:04:20 -05:00
import { csrfProtectionMiddleware } from "./middlewares/csrfProtection" ;
2024-12-12 22:46:58 -05:00
import helmet from "helmet" ;
2025-07-14 18:00:41 -07:00
import rateLimit from "express-rate-limit" ;
import createHttpError from "http-errors" ;
import HttpCode from "./types/HttpCode" ;
2025-07-14 22:21:04 -07:00
import requestTimeoutMiddleware from "./middlewares/requestTimeout" ;
2025-07-16 15:50:03 -07:00
import { createStore } from "./lib/rateLimitStore" ;
2024-12-07 22:07:13 -05:00
2025-03-31 10:10:28 -04:00
const dev = config . isDev ;
2025-01-01 17:50:12 -05:00
const externalPort = config . getRawConfig ( ) . server . external_port ;
2024-12-07 22:07:13 -05:00
export function createApiServer() {
2024-12-12 22:46:58 -05:00
const apiServer = express ( ) ;
2025-07-13 21:57:24 -07:00
const prefix = ` /api/v1 ` ;
2024-12-12 22:46:58 -05:00
2025-06-19 11:22:29 -04:00
const trustProxy = config . getRawConfig ( ) . server . trust_proxy ;
if ( trustProxy ) {
apiServer . set ( "trust proxy" , trustProxy ) ;
2025-01-15 23:26:31 -05:00
}
2025-01-13 23:59:10 -05:00
const corsConfig = config . getRawConfig ( ) . server . cors ;
const options = {
. . . ( corsConfig ? . origins
? { origin : corsConfig.origins }
: {
origin : ( origin : any , callback : any ) = > {
callback ( null , true ) ;
}
} ) ,
. . . ( corsConfig ? . methods && { methods : corsConfig.methods } ) ,
. . . ( corsConfig ? . allowed_headers && {
allowedHeaders : corsConfig.allowed_headers
} ) ,
credentials : ! ( corsConfig ? . credentials === false )
} ;
logger . debug ( "Using CORS options" , options ) ;
apiServer . use ( cors ( options ) ) ;
if ( ! dev ) {
2024-12-12 22:46:58 -05:00
apiServer . use ( helmet ( ) ) ;
2024-12-25 22:04:20 -05:00
apiServer . use ( csrfProtectionMiddleware ) ;
2024-12-12 22:46:58 -05:00
}
2024-12-25 22:04:20 -05:00
2024-12-12 22:46:58 -05:00
apiServer . use ( cookieParser ( ) ) ;
apiServer . use ( express . json ( ) ) ;
2025-07-13 21:57:24 -07:00
// Add request timeout middleware
apiServer . use ( requestTimeoutMiddleware ( 60000 ) ) ; // 60 second timeout
2024-12-12 22:46:58 -05:00
if ( ! dev ) {
apiServer . use (
2025-07-14 18:00:41 -07:00
rateLimit ( {
windowMs :
config . getRawConfig ( ) . rate_limits . global . window_minutes *
60 *
1000 ,
2025-01-01 17:50:12 -05:00
max : config.getRawConfig ( ) . rate_limits . global . max_requests ,
2025-07-14 18:00:41 -07:00
keyGenerator : ( req ) = > ` apiServerGlobal: ${ req . ip } : ${ req . path } ` ,
handler : ( req , res , next ) = > {
const message = ` Rate limit exceeded. You can make ${ config . getRawConfig ( ) . rate_limits . global . max_requests } requests every ${ config . getRawConfig ( ) . rate_limits . global . window_minutes } minute(s). ` ;
return next (
createHttpError ( HttpCode . TOO_MANY_REQUESTS , message )
) ;
2025-07-16 15:50:03 -07:00
} ,
store : createStore ( )
2024-12-25 22:04:20 -05:00
} )
2024-12-12 22:46:58 -05:00
) ;
}
// API routes
apiServer . use ( logIncomingMiddleware ) ;
apiServer . use ( prefix , unauthenticated ) ;
apiServer . use ( prefix , authenticated ) ;
// WebSocket routes
apiServer . use ( prefix , wsRouter ) ;
// Error handling
apiServer . use ( notFoundMiddleware ) ;
apiServer . use ( errorHandlerMiddleware ) ;
// Create HTTP server
const httpServer = apiServer . listen ( externalPort , ( err? : any ) = > {
if ( err ) throw err ;
logger . info (
2024-12-25 22:04:20 -05:00
` API server is running on http://localhost: ${ externalPort } `
2024-12-12 22:46:58 -05:00
) ;
} ) ;
// Handle WebSocket upgrades
handleWSUpgrade ( httpServer ) ;
return httpServer ;
2024-12-07 22:07:13 -05:00
}