Ctrl K
ComunidadGuías…

mockups/server.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env node
// Zero-dependency static server for the mockups. Run: node mockups/server.js [port]
const http = require("node:http");
const fs = require("node:fs");
const path = require("node:path");
const { execFileSync } = require("node:child_process");

const ROOT = __dirname;
const PORT = Number(process.argv[2] || process.env.PORT || 4000);
const CSS_ROUTE = "/assets/tailwind.css";
const CACHE_DIR = path.join(ROOT, ".cache");
const CSS_OUT = path.join(CACHE_DIR, "tailwind.css");

const TYPES = {
  ".html": "text/html; charset=utf-8",
  ".css": "text/css; charset=utf-8",
  ".js": "text/javascript; charset=utf-8",
  ".svg": "image/svg+xml",
  ".json": "application/json",
};

// bin/tailwindcss is gitignored, so a linked worktree has none of its own: fall back to the main checkout's.
function findTailwind() {
  const candidates = [process.env.TAILWIND, path.join(ROOT, "..", "bin", "tailwindcss")];
  try {
    const common = execFileSync("git", ["-C", ROOT, "rev-parse", "--path-format=absolute", "--git-common-dir"], {
      encoding: "utf8",
    }).trim();
    candidates.push(path.join(common, "..", "bin", "tailwindcss"));
  } catch {
    // not in a git checkout; the other candidates still apply
  }
  return candidates.find((p) => p && fs.existsSync(p));
}

function sources() {
  const pages = fs.readdirSync(ROOT).filter((f) => /\.(html|js)$/.test(f) && f !== "server.js");
  return [
    path.join(ROOT, "input.css"),
    path.join(ROOT, "..", "tailwind", "input.css"),
    path.join(ROOT, "..", "cmd", "server", "frontend", "static", "code-themes.css"),
  ].concat(
    pages.map((f) => path.join(ROOT, f)),
  );
}

function buildCSS() {
  const built = fs.existsSync(CSS_OUT) ? fs.statSync(CSS_OUT).mtimeMs : 0;
  if (sources().every((f) => fs.statSync(f).mtimeMs <= built)) return;
  const bin = findTailwind();
  if (!bin) {
    throw new Error("Tailwind CLI not found. Run `make setup-tailwind` or set TAILWIND=/path/to/tailwindcss.");
  }
  fs.mkdirSync(CACHE_DIR, { recursive: true });
  execFileSync(bin, ["-i", path.join(ROOT, "input.css"), "-o", CSS_OUT], { stdio: ["ignore", "ignore", "pipe"] });
}

function resolveFile(urlPath) {
  const rel = decodeURIComponent(urlPath).replace(/^\/+/, "");
  const abs = path.resolve(ROOT, rel || "index.html");
  if (abs !== ROOT && !abs.startsWith(ROOT + path.sep)) return null;
  if (abs.startsWith(CACHE_DIR)) return null;
  for (const candidate of [abs, abs + ".html", path.join(abs, "index.html")]) {
    if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) return candidate;
  }
  return null;
}

http
  .createServer((req, res) => {
    const { pathname } = new URL(req.url, "http://localhost");
    try {
      let file;
      if (pathname === CSS_ROUTE) {
        buildCSS();
        file = CSS_OUT;
      } else {
        file = resolveFile(pathname);
      }
      if (!file) {
        res.writeHead(404, { "content-type": "text/plain" }).end("Not found");
        return;
      }
      res.writeHead(200, {
        "content-type": TYPES[path.extname(file)] || "application/octet-stream",
        "cache-control": "no-store",
      });
      fs.createReadStream(file).pipe(res);
    } catch (err) {
      res.writeHead(500, { "content-type": "text/plain" }).end(String(err.message || err));
    }
  })
  .listen(PORT, () => console.log(`Mockups: http://localhost:${PORT}`));