UNPKG

kist

Version:

Lightweight Package Pipeline Processor with Plugin Architecture

139 lines 5.68 kB
import { __awaiter } from "tslib"; import express from "express"; import rateLimit from "express-rate-limit"; import path from "path"; import { WebSocket, WebSocketServer } from "ws"; import { AbstractProcess } from "../core/abstract/AbstractProcess.js"; import { ConfigStore } from "../core/config/ConfigStore.js"; export class LiveServer extends AbstractProcess { constructor() { super(); this.app = express(); this.clients = new Set(); const configStore = ConfigStore.getInstance(); const liveReloadOptions = configStore.get("options.live") || {}; this.port = liveReloadOptions.port || 3000; this.root = path.resolve(process.cwd(), liveReloadOptions.root || "public"); this.watchPaths = (liveReloadOptions.watchPaths || [ "src/**/*", "config/**/*", "pack.yaml", ]).map((p) => path.resolve(process.cwd(), p)); this.ignoredPaths = (liveReloadOptions.ignoredPaths || ["node_modules"]).map((p) => path.resolve(process.cwd(), p)); this.logInitializationDetails(); this.server = this.app.listen(this.port, () => { this.logInfo(`Live Server running at http://localhost:${this.port}`); }); this.wss = new WebSocketServer({ server: this.server }); this.setupRateLimiter(); this.setupWebSocketHandlers(); this.setupMiddleware(); } initializeServer() { this.server = this.app.listen(this.port, () => { this.logInfo(`Live Server running at http://localhost:${this.port}`); }); this.wss = new WebSocketServer({ server: this.server }); } logInitializationDetails() { this.logInfo(`LiveServer initialized with port: ${this.port}`); this.logInfo(`Serving static files from: ${this.root}`); this.logInfo(`Watching paths: ${JSON.stringify(this.watchPaths)}`); this.logInfo(`Ignoring paths: ${JSON.stringify(this.ignoredPaths)}`); } setupRateLimiter() { const limiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 100, message: "Too many requests from this IP, please try again later.", }); this.app.use(limiter); } setupWebSocketHandlers() { this.wss.on("connection", (ws) => { this.logInfo("New WebSocket connection established."); this.clients.add(ws); ws.on("message", (message) => { this.logInfo(`WebSocket message received: ${message.toString()}`); }); ws.on("close", () => { this.logInfo("WebSocket connection closed."); this.clients.delete(ws); }); ws.on("error", (error) => { console.error("WebSocket encountered an error:", error); this.clients.delete(ws); }); }); } setupMiddleware() { this.logInfo(`Resolved public directory: ${this.root}`); this.logInfo(`Serving static files from: ${this.root}`); this.app.use(express.static(this.root)); this.app.use(this.injectLiveReloadScript.bind(this)); } injectLiveReloadScript(req, res, next) { if (req.url.endsWith(".html")) { const sanitizedPath = path.join(path.resolve(__dirname, "public"), path.normalize(req.url).replace(/^(\.\.(\/|\\|$))+/g, "")); res.sendFile(sanitizedPath, (err) => { if (err) { console.error("Error sending HTML file:", err); next(err); } else { res.write(`<script> const ws = new WebSocket("ws://localhost:${this.port}"); ws.onmessage = (event) => { if (event.data === "reload") { this.logInfo("Reloading page..."); window.location.reload(); } }; </script>`); res.end(); } }); } else { next(); } } reloadClients() { this.logInfo("Reloading all connected clients..."); this.clients.forEach((client) => { if (client.readyState === WebSocket.OPEN) { client.send("reload"); } }); } shutdown() { return __awaiter(this, void 0, void 0, function* () { this.logInfo("Shutting down Live Reload Server..."); this.clients.forEach((client) => client.close()); this.wss.close(); yield new Promise((resolve, reject) => { this.server.close((err) => { if (err) { if (this.isErrnoException(err) && err.code === "ERR_SERVER_NOT_RUNNING") { this.logWarn("Server is not running, skipping shutdown."); resolve(); } else { this.logError("Error shutting down server:", err); reject(err); } } else { resolve(); } }); }); this.logInfo("Live Reload Server has been shut down."); }); } isErrnoException(error) { return typeof error === "object" && error !== null && "code" in error; } } //# sourceMappingURL=LiveServer.js.map