// src/index.ts
import express from "express";
import vm from "node:vm";
import { execFileSync } from "node:child_process";
import path from "node:path";
import { fileURLToPath } from "node:url";
var __dirname = path.dirname(fileURLToPath(import.meta.url));
var PORT = parseInt(process.env.NODEJS_EXECUTOR_PORT ?? "", 10) || 3020;
var HOST = process.env.NODEJS_EXECUTOR_HOST ?? "localhost";
var BODY_LIMIT = process.env.NODEJS_EXECUTOR_BODY_LIMIT ?? "10mb";
var USER_PACKAGES_DIR = process.env.NODEJS_USER_PACKAGES_DIR ?? path.join(__dirname, "..", "user-packages");
var app = express();
app.use(express.json({ limit: BODY_LIMIT }));
app.get("/health", (_req, res) => {
  res.json({
    status: "healthy",
    service: "nodejs-executor",
    node_version: process.version
  });
});
app.post("/execute", (req, res) => {
  const { code, input_data = {}, timeout = 3e4 } = req.body;
  if (!code || typeof code !== "string") {
    res.status(400).json({ success: false, error: 'Missing or invalid "code" field' });
    return;
  }
  const startTime = Date.now();
  const consoleOutput = [];
  const capturedConsole = {
    log: (...args) => consoleOutput.push(args.map(String).join(" ")),
    error: (...args) => consoleOutput.push(`[ERROR] ${args.map(String).join(" ")}`),
    warn: (...args) => consoleOutput.push(`[WARN] ${args.map(String).join(" ")}`),
    info: (...args) => consoleOutput.push(args.map(String).join(" "))
  };
  const sandbox = {
    console: capturedConsole,
    input_data,
    output: void 0,
    JSON,
    Math,
    Date,
    Array,
    Object,
    String,
    Number,
    Boolean,
    RegExp,
    Map,
    Set,
    Promise,
    setTimeout,
    setInterval,
    clearTimeout,
    clearInterval
  };
  try {
    const context = vm.createContext(sandbox);
    vm.runInContext(code, context, { timeout, filename: "user-code.js" });
    res.json({
      success: true,
      output: sandbox.output,
      console_output: consoleOutput.join("\n"),
      execution_time_ms: Date.now() - startTime
    });
  } catch (error) {
    res.json({
      success: false,
      error: error instanceof Error ? error.message : String(error),
      console_output: consoleOutput.join("\n"),
      execution_time_ms: Date.now() - startTime
    });
  }
});
app.post("/packages/install", (req, res) => {
  const { packages } = req.body;
  if (!packages || !Array.isArray(packages) || packages.length === 0) {
    res.status(400).json({ success: false, error: 'Missing or invalid "packages" array' });
    return;
  }
  const validPattern = /^(@[\w-]+\/)?[\w-]+(@[\w.-]+)?$/;
  const invalid = packages.filter((p) => !validPattern.test(p));
  if (invalid.length > 0) {
    res.status(400).json({ success: false, error: `Invalid package names: ${invalid.join(", ")}` });
    return;
  }
  try {
    execFileSync("npm", ["install", ...packages], { cwd: USER_PACKAGES_DIR, timeout: 6e4 });
    res.json({ success: true, message: `Installed: ${packages.join(", ")}` });
  } catch (error) {
    res.status(500).json({ success: false, error: error instanceof Error ? error.message : String(error) });
  }
});
app.get("/packages", (_req, res) => {
  try {
    const output = execFileSync("npm", ["list", "--json", "--depth=0"], { cwd: USER_PACKAGES_DIR, encoding: "utf-8" });
    res.json({ success: true, packages: JSON.parse(output).dependencies || {} });
  } catch {
    res.json({ success: true, packages: {} });
  }
});
app.use((err, _req, res, _next) => {
  console.error("Server error:", err);
  res.status(500).json({ success: false, error: "Internal server error" });
});
app.listen(PORT, HOST, () => {
  console.log(`Node.js Executor running on http://${HOST}:${PORT}`);
});
