| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- "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
- });
|