UNPKG

@ajayos/server

Version:

A lightweight Express-based HTTP/HTTPS server wrapper with built-in middleware, lifecycle hooks, logging, and utility helpers.

397 lines (382 loc) 12.7 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { Application: () => import_express3.Application, Router: () => import_express3.Router, SERVER: () => SERVER, bodyParser: () => bodyParser, compression: () => compression, cookieParser: () => cookieParser, cors: () => cors, default: () => SERVER, express: () => express3, helmet: () => helmet, jsonError: () => jsonError, morgan: () => morgan, rateLimit: () => rateLimit, static: () => staticPlugin, timeout: () => timeout }); module.exports = __toCommonJS(index_exports); // src/server.ts var import_express2 = __toESM(require("express"), 1); var http = __toESM(require("http"), 1); var https = __toESM(require("https"), 1); var os = __toESM(require("os"), 1); var import_config = require("dotenv/config"); // src/plugins/cors.ts var import_cors = __toESM(require("cors"), 1); var cors = (options) => ({ name: "cors", setup: (app) => app.use((0, import_cors.default)(options)) }); // src/plugins/static.ts var import_express = __toESM(require("express"), 1); var staticPlugin = (root, options) => ({ name: "static", setup: (app) => app.use(import_express.default.static(root, options)) }); // src/plugins/morgan.ts var import_morgan = __toESM(require("morgan"), 1); var morgan = (format = "dev") => ({ name: "request-logger", setup: (app) => app.use((0, import_morgan.default)(format)) }); // src/plugins/helmet.ts var import_helmet = __toESM(require("helmet"), 1); var helmet = (options) => ({ name: "helmet", setup: (app) => app.use((0, import_helmet.default)(options)) }); // src/plugins/timeout.ts var import_connect_timeout = __toESM(require("connect-timeout"), 1); var timeout = (time, options) => ({ name: "timeout", setup: (app) => app.use((0, import_connect_timeout.default)(time, options)) }); // src/plugins/jsonError.ts var jsonError = (handler) => ({ name: "json-error", setup: (app) => { app.use((err, req, res, next) => { if (err instanceof SyntaxError && "body" in err && req.headers["content-type"]?.includes("application/json")) { if (typeof handler === "function") { return handler(err, req, res); } return res.status(400).json(handler ?? { error: "Invalid JSON payload" }); } next(err); }); } }); // src/plugins/rateLimit.ts var import_express_rate_limit = __toESM(require("express-rate-limit"), 1); var rateLimit = (options) => ({ name: "rate-limit", setup: (app) => app.use((0, import_express_rate_limit.default)(options)) }); // src/plugins/bodyParser.ts var import_body_parser = require("body-parser"); var bodyParser = (options) => ({ name: "body-parser", setup: (app) => app.use((0, import_body_parser.json)(options), (0, import_body_parser.urlencoded)({ extended: true })) }); // src/plugins/compression.ts var import_compression = __toESM(require("compression"), 1); var compression = (options) => ({ name: "compression", setup: (app) => app.use((0, import_compression.default)(options)) }); // src/plugins/cookieParser.ts var import_cookie_parser = __toESM(require("cookie-parser"), 1); var cookieParser = (secret, options) => ({ name: "cookieParser", async setup(app) { app.use((0, import_cookie_parser.default)(secret, options)); } }); // src/server.ts var BUILTIN_PLUGINS = { cors, helmet, morgan, static: staticPlugin, jsonError, rateLimit, bodyParser, compression }; var SERVER = class { /** * Initializes the SERVER instance. * Supports flexible arguments to allow instantiation via Port, Config, or Callbacks in various orders. * * @param arg1 - Port number OR Configuration object. * @param arg2 - Configuration object OR Callback function. * @param arg3 - Callback function. */ constructor(arg1, arg2, arg3) { /** Callback executed when the server starts listening. */ this.onServerStart = () => { }; /** Callback executed when a server error occurs. */ this.onServerError = () => { }; /** Manager instance for handling server plugins. */ this.plugins = []; /** Configuration object for the server. */ this.config = {}; this.app = (0, import_express2.default)(); let callback; if (typeof arg1 === "number") { this.port = arg1; if (typeof arg2 === "function") callback = arg2; if (typeof arg2 === "object") this.config = arg2; if (arg3) callback = arg3; } else if (typeof arg1 === "object") { this.config = arg1; this.port = arg1.port ?? Number(process.env.PORT) ?? 8123; if (typeof arg2 === "function") callback = arg2; } else { this.port = Number(process.env.PORT) ?? 8123; } for (const plugin of this.config.plugins ?? []) { this.plugins.push(plugin); } if (callback) { this.onServerStart = callback; } else if (this.config.onServerStart) { this.onServerStart = this.config.onServerStart; } if (this.config.onServerError) { this.onServerError = this.config.onServerError; } } /** * Starts the server. * * 1. Applies built-in middleware (CORS, BodyParser, etc.). * 2. Applies registered plugins. * 3. Creates the HTTP or HTTPS server. * 4. Listens on the specified port. * * @throws {Error} If HTTPS is enabled but SSL options are missing. */ start(callback) { this.applyBuiltins(); for (const plugin of this.plugins) { plugin.setup(this.app); } if (this.config.https) { const httpsOptions = typeof this.config.https === "object" ? this.config.https : void 0; if (!httpsOptions) { throw new Error("HTTPS enabled but no SSL options provided (key/cert)"); } this.server = https.createServer(httpsOptions, this.app); } else { this.server = http.createServer(this.app); } this.server.listen(this.port, this.onServerStart); this.server.on("error", this.onServerError); callback?.(); } /** * Closes the server and exits the process. */ close() { this.server?.close(() => { process.exit(0); }); } /** * Registers a new plugin to the server. * Plugins are applied to the Express app when `start()` is called. * * @param plugin - The plugin instance or function to register. */ usePlugin(plugin) { this.plugins.push(plugin); } /** * Applies built-in middleware based on the server configuration. * Supported built-ins include CORS, Helmet, BodyParser, CookieParser, and Static file serving. */ applyBuiltins() { for (const key in BUILTIN_PLUGINS) { const value = this.config[key]; if (!value) continue; const pluginFactory = BUILTIN_PLUGINS[key]; if (value === true) { this.plugins.push(pluginFactory()); } else { this.plugins.push(pluginFactory(value)); } } } /** * Retrieves a list of active IPv4 network interfaces (excluding internal localhost). * Useful for displaying access URLs in the console (e.g., http://192.168.1.5:8080). * * @returns A record where keys are interface names and values are arrays of IP addresses. */ getActiveNetworkInterfaces() { const nets = os.networkInterfaces(); const result = {}; for (const name in nets) { for (const net of nets[name] ?? []) { if (net.family === "IPv4" && !net.internal) { result[name] ??= []; result[name].push(net.address); } } } return result; } /** * Mounts specified middleware function(s) at the specified path. * If the path is not specified, it defaults to "/". * * @param handlers - Request handlers (middleware). */ use(...handlers) { this.app.use(...handlers); } /** * Routes HTTP GET requests to the specified path with the specified callback functions. * * @param path - The route path. * @param handlers - Callback functions to handle the request. */ get(path, ...handlers) { this.app.get(path, ...handlers); } /** * Routes HTTP POST requests to the specified path with the specified callback functions. * * @param path - The route path. * @param handlers - Callback functions to handle the request. */ post(path, ...handlers) { this.app.post(path, ...handlers); } /** * Routes HTTP PUT requests to the specified path with the specified callback functions. * * @param path - The route path. * @param handlers - Callback functions to handle the request. */ put(path, ...handlers) { this.app.put(path, ...handlers); } /** * Routes HTTP DELETE requests to the specified path with the specified callback functions. * * @param path - The route path. * @param handlers - Callback functions to handle the request. */ delete(path, ...handlers) { this.app.delete(path, ...handlers); } /** * Routes HTTP PATCH requests to the specified path with the specified callback functions. * * @param path - The route path. * @param handlers - Callback functions to handle the request. */ patch(path, ...handlers) { this.app.patch(path, ...handlers); } /** * Routes HTTP requests (all methods) to the specified path with the specified callback functions. * * @param path - The route path. * @param handlers - Callback functions to handle the request. */ all(path, ...handlers) { this.app.all(path, ...handlers); } /** * Registers an event listener on the underlying Express application. * * @param event - The event name. * @param listener - The callback function to execute when the event is emitted. */ on(event, listener) { this.server.on(event, listener); } /** * Removes an event listener from the underlying Express application. * @param event - The event name. * @param listener - The callback function to remove. */ off(event, listener) { this.server.off(event, listener); } /** * Registers a one-time event listener on the underlying Express application. * @param event - The event name. * @param listener - The callback function to execute when the event is emitted. */ once(event, listener) { this.server.once(event, listener); } /** * Registers an event listener on the underlying Express application. * @param event - The event name. * @param listener - The callback function to execute when the event is emitted. */ onApp(event, listener) { this.app.on(event, listener); } /** * Removes an event listener from the underlying Express application. * @param event - The event name. * @param listener - The callback function to remove. */ offApp(event, listener) { this.app.off(event, listener); } /** * Registers a one-time event listener on the underlying Express application. * @param event - The event name. * @param listener - The callback function to execute when the event is emitted. */ onceApp(event, listener) { this.app.once(event, listener); } }; // src/ext.ts var import_express3 = require("express"); var express3 = __toESM(require("express"), 1); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Application, Router, SERVER, bodyParser, compression, cookieParser, cors, express, helmet, jsonError, morgan, rateLimit, static, timeout });