const http = require("http");
const { markdownToHtml, htmlToPdf } = require("./convert");
const PORT = process.env.PORT || 3000;
const UPLOAD_PAGE = `
Markdown Converter
Markdown Converter
Convert Markdown to styled HTML or PDF with TOC and Mermaid diagrams
`;
function parseBody(req) {
return new Promise((resolve, reject) => {
const chunks = [];
let size = 0;
const limit = 10 * 1024 * 1024; // 10MB
req.on("data", (chunk) => {
size += chunk.length;
if (size > limit) {
reject(new Error("Request body too large"));
req.destroy();
return;
}
chunks.push(chunk);
});
req.on("end", () => resolve(Buffer.concat(chunks).toString()));
req.on("error", reject);
});
}
const server = http.createServer(async (req, res) => {
if (req.method === "GET" && (req.url === "/" || req.url === "")) {
res.writeHead(200, { "Content-Type": "text/html" });
res.end(UPLOAD_PAGE);
return;
}
if (req.method === "POST" && req.url === "/convert") {
try {
const body = JSON.parse(await parseBody(req));
const { markdown, format } = body;
if (!markdown) {
res.writeHead(400, { "Content-Type": "text/plain" });
res.end("Missing 'markdown' field");
return;
}
const html = markdownToHtml(markdown);
if (format === "pdf") {
const pdfBuffer = await htmlToPdf(html);
res.writeHead(200, {
"Content-Type": "application/pdf",
"Content-Disposition": "attachment; filename=output.pdf",
});
res.end(pdfBuffer);
} else {
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
res.end(html);
}
} catch (err) {
console.error("Convert error:", err);
res.writeHead(500, { "Content-Type": "text/plain" });
res.end("Conversion failed: " + err.message);
}
return;
}
// curl-friendly API: accepts raw markdown body, format via query param or Accept header
// Usage:
// curl -X POST --data-binary @file.md https://host/api/convert > output.html
// curl -X POST --data-binary @file.md https://host/api/convert?format=pdf -o output.pdf
if (req.method === "POST" && req.url.startsWith("/api/convert")) {
try {
const url = new URL(req.url, `http://${req.headers.host}`);
const formatParam = url.searchParams.get("format") || "html";
const markdown = await parseBody(req);
if (!markdown.trim()) {
res.writeHead(400, { "Content-Type": "text/plain" });
res.end("Empty body — POST raw markdown text");
return;
}
const html = markdownToHtml(markdown);
if (formatParam === "pdf") {
const pdfBuffer = await htmlToPdf(html);
res.writeHead(200, {
"Content-Type": "application/pdf",
"Content-Disposition": "attachment; filename=output.pdf",
});
res.end(pdfBuffer);
} else {
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
res.end(html);
}
} catch (err) {
console.error("API convert error:", err);
res.writeHead(500, { "Content-Type": "text/plain" });
res.end("Conversion failed: " + err.message);
}
return;
}
if (req.method === "GET" && req.url === "/health") {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ status: "ok" }));
return;
}
res.writeHead(404, { "Content-Type": "text/plain" });
res.end("Not found");
});
server.listen(PORT, () => {
console.log(`md2html server listening on http://0.0.0.0:${PORT}`);
});