import fastify from "fastify"; import dotenv from "dotenv"; import { getServerLogPath, v1Router, logServer, getJanExtensionsPath, } from "@janhq/core/node"; import { join } from "path"; // Load environment variables dotenv.config(); // Define default settings const JAN_API_HOST = process.env.JAN_API_HOST || "127.0.0.1"; const JAN_API_PORT = Number.parseInt(process.env.JAN_API_PORT || "1337"); // Initialize server settings let server: any | undefined = undefined; let hostSetting: string = JAN_API_HOST; let portSetting: number = JAN_API_PORT; let corsEnabled: boolean = true; let isVerbose: boolean = true; /** * Server configurations * @param host - The host address for the server * @param port - The port number for the server * @param isCorsEnabled - Flag to enable or disable CORS * @param isVerboseEnabled - Flag to enable or disable verbose logging * @param schemaPath - Path to the OpenAPI schema file * @param baseDir - Base directory for the OpenAPI schema file */ export interface ServerConfig { host?: string; port?: number; isCorsEnabled?: boolean; isVerboseEnabled?: boolean; schemaPath?: string; baseDir?: string; } /** * Function to start the server * @param configs - Server configurations */ export const startServer = async (configs?: ServerConfig) => { // Update server settings isVerbose = configs?.isVerboseEnabled ?? true; hostSetting = configs?.host ?? JAN_API_HOST; portSetting = configs?.port ?? JAN_API_PORT; corsEnabled = configs?.isCorsEnabled ?? true; const serverLogPath = getServerLogPath(); // Start the server try { // Log server start if (isVerbose) logServer(`Debug: Starting JAN API server...`); // Initialize Fastify server with logging server = fastify({ logger: { level: "info", file: serverLogPath, }, }); // Register CORS if enabled if (corsEnabled) await server.register(require("@fastify/cors"), {}); // Register Swagger for API documentation await server.register(require("@fastify/swagger"), { mode: "static", specification: { path: configs?.schemaPath ?? "./../docs/openapi/jan.yaml", baseDir: configs?.baseDir ?? "./../docs/openapi", }, }); // Register Swagger UI await server.register(require("@fastify/swagger-ui"), { routePrefix: "/", baseDir: configs?.baseDir ?? join(__dirname, "../..", "./docs/openapi"), uiConfig: { docExpansion: "full", deepLinking: false, }, staticCSP: false, transformSpecificationClone: true, }); // Register static file serving for extensions // TODO: Watch extension files changes and reload await server.register( (childContext: any, _: any, done: any) => { childContext.register(require("@fastify/static"), { root: getJanExtensionsPath(), wildcard: false, }); done(); }, { prefix: "extensions" } ); // Register API routes await server.register(v1Router, { prefix: "/v1" }); // Start listening for requests await server .listen({ port: portSetting, host: hostSetting, }) .then(() => { // Log server listening if (isVerbose) logServer( `Debug: JAN API listening at: http://${hostSetting}:${portSetting}` ); }); } catch (e) { // Log any errors if (isVerbose) logServer(`Error: ${e}`); } }; /** * Function to stop the server */ export const stopServer = async () => { try { // Log server stop if (isVerbose) logServer(`Debug: Server stopped`); // Stop the server await server.close(); } catch (e) { // Log any errors if (isVerbose) logServer(`Error: ${e}`); } };