@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
JavaScript
;
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
});