@mesh-tech/mesh-cli
Version:
CLI for Mesh platform development utilities
75 lines (74 loc) • 2.98 kB
JavaScript
import { createServer } from "node:http";
import { readFile } from "node:fs/promises";
import { extname, join, normalize, sep } from "node:path";
const CONTENT_TYPES = {
".html": "text/html; charset=utf-8",
".js": "text/javascript; charset=utf-8",
".mjs": "text/javascript; charset=utf-8",
".css": "text/css; charset=utf-8",
".json": "application/json; charset=utf-8",
".map": "application/json; charset=utf-8",
".svg": "image/svg+xml",
".png": "image/png",
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".gif": "image/gif",
".ico": "image/x-icon",
".woff": "font/woff",
".woff2": "font/woff2",
".txt": "text/plain; charset=utf-8",
".md": "text/markdown; charset=utf-8",
".webmanifest": "application/manifest+json",
};
export async function serveDocsSite(args) {
const root = normalize(args.root);
const rootPrefix = root.endsWith(sep) ? root : root + sep;
const server = createServer((req, res) => {
void (async () => {
const url = new URL(req.url ?? "/", "http://localhost");
const pathname = decodeURIComponent(url.pathname);
if (pathname === "/healthz") {
res.writeHead(200, { "content-type": "text/plain" }).end("ok");
return;
}
const candidates = [
pathname,
`${pathname}.html`,
`${pathname.replace(/\/$/, "")}/index.html`,
];
if (pathname !== "/")
candidates.push("/index.html");
for (const candidate of candidates) {
const filePath = normalize(join(root, candidate));
if (filePath !== root && !filePath.startsWith(rootPrefix))
continue;
try {
const body = await readFile(filePath);
const type = CONTENT_TYPES[extname(filePath)] ?? "application/octet-stream";
const cache = candidate.includes("/assets/") ? "public, max-age=31536000, immutable" : "no-cache";
res.writeHead(200, { "content-type": type, "cache-control": cache });
res.end(body);
return;
}
catch {
}
}
res.writeHead(404, { "content-type": "text/plain" }).end("not found");
})().catch(() => {
res.writeHead(500).end("internal error");
});
});
await new Promise((resolve, reject) => {
server.once("error", reject);
server.listen(args.port, "127.0.0.1", () => resolve());
});
const address = server.address();
const port = typeof address === "object" && address ? address.port : args.port;
return {
url: `http://127.0.0.1:${port}`,
port,
close: () => new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
}),
};
}