Files
magic-resume/server.mjs

144 lines
4.1 KiB
JavaScript

import { createServer } from "node:http";
import { createReadStream, existsSync, statSync } from "node:fs";
import { extname, normalize, resolve } from "node:path";
import { Readable } from "node:stream";
import serverEntry from "./dist/server/server.js";
const clientDir = resolve(process.cwd(), "dist/client");
const port = Number(process.env.PORT || 3000);
const host = process.env.HOSTNAME || "0.0.0.0";
const MIME_TYPES = {
".css": "text/css; charset=utf-8",
".gif": "image/gif",
".html": "text/html; charset=utf-8",
".ico": "image/x-icon",
".jpeg": "image/jpeg",
".jpg": "image/jpeg",
".js": "text/javascript; charset=utf-8",
".json": "application/json; charset=utf-8",
".map": "application/json; charset=utf-8",
".png": "image/png",
".svg": "image/svg+xml",
".txt": "text/plain; charset=utf-8",
".ttf": "font/ttf",
".webp": "image/webp",
".woff": "font/woff",
".woff2": "font/woff2",
".xml": "application/xml; charset=utf-8"
};
function getContentType(filePath) {
const extension = extname(filePath).toLowerCase();
return MIME_TYPES[extension] || "application/octet-stream";
}
function toHeaders(nodeHeaders) {
const headers = new Headers();
for (const [key, value] of Object.entries(nodeHeaders)) {
if (typeof value === "undefined") continue;
if (Array.isArray(value)) {
for (const item of value) headers.append(key, item);
} else {
headers.set(key, value);
}
}
return headers;
}
function resolveStaticFile(pathname) {
const decoded = decodeURIComponent(pathname);
const normalized = normalize(decoded).replace(/^[/\\]+/, "");
const absolutePath = resolve(clientDir, normalized);
if (!absolutePath.startsWith(clientDir)) return null;
if (!existsSync(absolutePath)) return null;
const stats = statSync(absolutePath);
if (!stats.isFile()) return null;
return absolutePath;
}
function tryServeStatic(req, res, url) {
if (!url.pathname || url.pathname.endsWith("/")) return false;
const filePath = resolveStaticFile(url.pathname);
if (!filePath) return false;
res.statusCode = 200;
res.setHeader("Content-Type", getContentType(filePath));
if (url.pathname.startsWith("/assets/")) {
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
} else {
res.setHeader("Cache-Control", "public, max-age=3600");
}
if (req.method === "HEAD") {
res.end();
return true;
}
createReadStream(filePath).pipe(res);
return true;
}
function appendSetCookie(res, value) {
const existing = res.getHeader("set-cookie");
if (!existing) {
res.setHeader("set-cookie", value);
return;
}
if (Array.isArray(existing)) {
res.setHeader("set-cookie", [...existing, value]);
return;
}
res.setHeader("set-cookie", [String(existing), value]);
}
createServer(async (req, res) => {
try {
const hostHeader = req.headers.host || `localhost:${port}`;
const protocol = (req.headers["x-forwarded-proto"] || "http").toString().split(",")[0].trim();
const url = new URL(req.url || "/", `${protocol}://${hostHeader}`);
if (tryServeStatic(req, res, url)) return;
const method = (req.method || "GET").toUpperCase();
const hasBody = method !== "GET" && method !== "HEAD";
const init = {
method,
headers: toHeaders(req.headers)
};
if (hasBody) {
init.body = Readable.toWeb(req);
init.duplex = "half";
}
const request = new Request(url, init);
const response = await serverEntry.fetch(request);
res.statusCode = response.status;
response.headers.forEach((value, key) => {
if (key.toLowerCase() === "set-cookie") {
appendSetCookie(res, value);
} else {
res.setHeader(key, value);
}
});
if (method === "HEAD" || !response.body) {
res.end();
return;
}
Readable.fromWeb(response.body).pipe(res);
} catch (error) {
console.error("Server error:", error);
if (!res.headersSent) {
res.statusCode = 500;
res.setHeader("Content-Type", "text/plain; charset=utf-8");
}
res.end("Internal Server Error");
}
}).listen(port, host, () => {
console.log(`Server running at http://${host}:${port}`);
});