"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { WebContainerServer: () => WebContainerServer }); module.exports = __toCommonJS(src_exports); var import_socket = require("socket.io"); var import_child_process = require("child_process"); var import_promises = __toESM(require("fs/promises"), 1); var import_path = __toESM(require("path"), 1); var WebContainerServer = class { constructor(config = {}) { this.workspaces = /* @__PURE__ */ new Map(); this.processes = /* @__PURE__ */ new Map(); this.config = { port: config.port || 3e3, host: config.host || "localhost", workspaceRoot: config.workspaceRoot || import_path.default.join(process.cwd(), "workspaces") }; this.io = new import_socket.Server({ cors: { origin: "*", methods: ["GET", "POST"] } }); this.setupSocketHandlers(); } start() { import_promises.default.mkdir(this.config.workspaceRoot, { recursive: true }).then(() => { this.io.listen(this.config.port); console.log(`WebContainer Server is running on http://${this.config.host}:${this.config.port}`); console.log(`Workspace root: ${this.config.workspaceRoot}`); }).catch((error) => { console.error("Failed to create workspace directory:", error); process.exit(1); }); return this; } setupSocketHandlers() { this.io.on("connection", (socket) => { const workspaceId = Math.random().toString(36).substr(2, 9); const workspacePath = import_path.default.join(this.config.workspaceRoot, workspaceId); this.workspaces.set(socket.id, workspacePath); this.processes.set(socket.id, []); console.log(`Client connected. Workspace created at: ${workspacePath}`); socket.on("mount", async (files, callback) => { try { await this.handleMount(workspacePath, files); callback({ success: true }); } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error occurred"; callback({ error: errorMessage }); } }); socket.on("spawn", async (data, callback) => { try { const result = await this.handleSpawn(socket.id, workspacePath, data.command, data.args); callback({ success: true, result }); } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error occurred"; callback({ error: errorMessage }); } }); socket.on("fs:list", async (path2, callback) => { try { const result = await this.handleList(workspacePath, path2); callback({ success: true, result }); } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error occurred"; callback({ error: errorMessage }); } }); socket.on("fs:read", async (path2, callback) => { try { const result = await this.handleRead(workspacePath, path2); callback({ success: true, result }); } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error occurred"; callback({ error: errorMessage }); } }); socket.on("fs:write", async (data, callback) => { try { await this.handleWrite(workspacePath, data.path, data.content); callback({ success: true }); } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error occurred"; callback({ error: errorMessage }); } }); socket.on("fs:delete", async (path2, callback) => { try { await this.handleDelete(workspacePath, path2); callback({ success: true }); } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error occurred"; callback({ error: errorMessage }); } }); socket.on("fs:mkdir", async (path2, callback) => { try { await this.handleMkdir(workspacePath, path2); callback({ success: true }); } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error occurred"; callback({ error: errorMessage }); } }); socket.on("disconnect", () => { console.log(`Client disconnected. Cleaning up workspace: ${workspacePath}`); this.killAllProcesses(socket.id); import_promises.default.rm(workspacePath, { recursive: true, force: true }).catch((error) => console.error(`Failed to cleanup workspace: ${error}`)); this.workspaces.delete(socket.id); this.processes.delete(socket.id); }); }); } killAllProcesses(socketId) { const processes = this.processes.get(socketId) || []; for (const process2 of processes) { try { process2.kill("SIGTERM"); console.log(`Process ${process2.pid} terminated`); } catch (error) { console.error(`Failed to kill process ${process2.pid}:`, error); } } } async handleMount(workspacePath, files) { await import_promises.default.mkdir(workspacePath, { recursive: true }); await this.createFiles(workspacePath, files); } async createFiles(basePath, files) { for (const [name, item] of Object.entries(files)) { const fullPath = import_path.default.join(basePath, name); if ("file" in item) { await import_promises.default.writeFile(fullPath, item.file.contents); } else if ("directory" in item) { await import_promises.default.mkdir(fullPath, { recursive: true }); await this.createFiles(fullPath, item.directory.contents); } } } async handleSpawn(socketId, workspacePath, command, args = []) { return new Promise((resolve, reject) => { this.io.to(socketId).emit("process:output", { type: "stdout", data: `\r $ ${command} ${args.join(" ")}\r ` }); const process2 = (0, import_child_process.spawn)(command, args, { cwd: workspacePath, stdio: ["pipe", "pipe", "pipe"] }); const processes = this.processes.get(socketId) || []; processes.push(process2); this.processes.set(socketId, processes); let stdout = ""; let stderr = ""; process2.stdout.on("data", (data) => { const output = data.toString(); stdout += output; console.log(`[${command}] stdout:`, output); this.io.to(socketId).emit("process:output", { type: "stdout", data: output }); }); process2.stderr.on("data", (data) => { const output = data.toString(); stderr += output; console.error(`[${command}] stderr:`, output); this.io.to(socketId).emit("process:output", { type: "stderr", data: output }); }); process2.on("close", (code) => { const processes2 = this.processes.get(socketId) || []; const index = processes2.indexOf(process2); if (index > -1) { processes2.splice(index, 1); } this.io.to(socketId).emit("process:output", { type: "exit", data: `\r Process exited with code ${code}\r $ ` }); if (code === 0) { resolve({ code, stdout, stderr }); } else { reject(new Error(`Process exited with code ${code} ${stderr}`)); } }); process2.on("error", (error) => { const processes2 = this.processes.get(socketId) || []; const index = processes2.indexOf(process2); if (index > -1) { processes2.splice(index, 1); } this.io.to(socketId).emit("process:output", { type: "stderr", data: `\r Error: ${error.message}\r $ ` }); reject(error); }); }); } async handleList(workspacePath, relativePath) { const fullPath = import_path.default.join(workspacePath, relativePath); const entries = await import_promises.default.readdir(fullPath, { withFileTypes: true }); return entries.map((entry) => ({ name: entry.name, type: entry.isDirectory() ? "directory" : "file" })); } async handleRead(workspacePath, relativePath) { const fullPath = import_path.default.join(workspacePath, relativePath); return import_promises.default.readFile(fullPath, "utf-8"); } async handleWrite(workspacePath, relativePath, content) { const fullPath = import_path.default.join(workspacePath, relativePath); await import_promises.default.mkdir(import_path.default.dirname(fullPath), { recursive: true }); await import_promises.default.writeFile(fullPath, content); } async handleDelete(workspacePath, relativePath) { const fullPath = import_path.default.join(workspacePath, relativePath); await import_promises.default.rm(fullPath, { recursive: true, force: true }); } async handleMkdir(workspacePath, relativePath) { const fullPath = import_path.default.join(workspacePath, relativePath); await import_promises.default.mkdir(fullPath, { recursive: true }); } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { WebContainerServer });