kumo-enjin
v1.0.0
Published
雲エンジン (Cloud Engine) - Transform your VPS into a WebContainer-like development environment
Maintainers
Readme
Kumo Enjin (雲エンジン) - Cloud Engine
Transform your VPS into a WebContainer-like development environment, similar to StackBlitz's WebContainer and Daytona. Connect securely via SSH and manage your remote development workflow seamlessly.
Features
🔐 Secure SSH Connection - Support for both password and SSH key authentication
📁 File Operations - Upload/download files and directories with progress tracking
🖥️ Remote Command Execution - Run commands interactively with real-time streaming output
🌐 Smart Port Management - Public URLs or local port forwarding
🔄 Auto-Reconnection - Gracefully handle connection drops with retry logic
🏗️ Session Isolation - Each project operates in its own working directory
⚙️ Dual API Design - Both simplified and advanced APIs available
🛡️ Security Best Practices - Command sanitization and secure credential handling
📝 Full TypeScript Support - Complete type definitions and JSDoc comments
🚀 Template Mounting - Direct project template deployment without local files
Installation
npm install kumo-enjinQuick Start (Simplified API)
import { KumoEnjin } from "kumo-enjin";
const enjin = new KumoEnjin({
host: "your-vps.com",
username: "user",
password: "password" // or privateKey: "/path/to/key"
});
await enjin.connect();
// Mount project files directly (no local files needed)
await enjin.mount({
directory: {
"package.json": {
file: {
contents: JSON.stringify({
name: "express-app",
version: "1.0.0",
main: "index.js",
scripts: {
dev: "node index.js"
},
dependencies: {
express: "^4.18.0"
}
}, null, 2)
}
},
"index.js": {
file: {
contents: `
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.send('Hello from Kumo Enjin + Express!');
});
app.listen(port, '0.0.0.0', () => {
console.log(\`🚀 Express server running at http://localhost:\${port}\`);
});
`.trim()
}
}
}
});
// Install dependencies (auto uses project directory)
await enjin.run("npm install", { stream: true });
// Start dev server (returns public URL)
const { url } = await enjin.start(); // defaults: 'npm run dev', port 5173
console.log(`🌐 Live at: ${url}`);
// One-click cleanup: stops server, deletes files, disconnects
await enjin.stopDevServer();
await enjin.cleanup();Advanced API Usage
import { KumoEnjin } from "kumo-enjin";
const enjin = new KumoEnjin({
host: "your-vps.com",
port: 22,
username: "user",
privateKey: "/path/to/your/private/key"
});
// Connect to your VPS
await enjin.connect();
// Upload your project
await enjin.upload("./my-app", "/remote/my-app");
// Install dependencies
await enjin.exec("npm install", { cwd: "/remote/my-app" });
// Start development server with port forwarding
const { url, pid } = await enjin.startDevServer("npm run dev", {
cwd: "/remote/my-app",
port: 3000,
usePublicUrl: false // Use local port forwarding instead
});
console.log("Preview at:", url);
// Stop server when done
await enjin.stop(pid);
await enjin.disconnect();Configuration
Basic Configuration
const config = {
host: "your-vps.com",
port: 22, // optional, defaults to 22
username: "user",
// Authentication (choose one)
password: "your-password",
// OR
privateKey: "/path/to/private/key",
passphrase: "key-passphrase", // optional
// Connection settings
timeout: 10000, // optional, defaults to 10s
// Auto-reconnection
autoReconnect: {
enabled: true,
maxRetries: 3,
retryDelay: 2000
}
};API Reference
Constructor
new KumoEnjin(config: KumoEnjinConfig)Connection Methods
connect()- Establish SSH connectiondisconnect()- Close SSH connection and cleanupisConnected()- Check connection status
Simplified API Methods
mount(template, templateName?)- Mount project template to remote serverrun(command, options?)- Execute command in project directorystart(command?, port?)- Start dev server with public URLstopDevServer()- Stop server, cleanup files, and disconnect
Advanced API Methods
exec(command, options)- Execute remote command with full controlupload(localPath, remotePath)- Upload files/directoriesdownload(remotePath, localPath)- Download files/directoriesstartDevServer(command, options)- Start dev server with advanced optionsstop(pid)- Stop specific process by PID
Utility Methods
getRunningProcesses()- Get map of running processesgetActivePortForwards()- Get active port forwarding mappings
Project Templates
Simple Static Site
const staticTemplate = {
directory: {
"index.html": {
file: { contents: "<h1>Hello World!</h1>" }
},
"style.css": {
file: { contents: "body { font-family: Arial; }" }
}
}
};
await enjin.mount(staticTemplate);
await enjin.start("python3 -m http.server 8000", 8000);Node.js Project
const nodeTemplate = {
directory: {
"package.json": {
file: { contents: JSON.stringify({
name: "my-node-app",
scripts: {
dev: "node server.js"
},
dependencies: {
express: "^4.18.0"
}
}, null, 2) }
},
"server.js": {
file: { contents: `
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.send('Hello from Kumo Enjin!');
});
app.listen(port, '0.0.0.0', () => {
console.log(\`Server running at http://localhost:\${port}\`);
});
`.trim() }
}
}
};
await enjin.mount(nodeTemplate);
await enjin.run("npm install");
await enjin.start("npm run dev", 3000);Multiple Templates
const templates = {
"vite-vanilla": {
directory: {
"package.json": { file: { contents: "..." } },
"index.html": { file: { contents: "..." } }
}
},
"express-api": {
directory: {
"package.json": { file: { contents: "..." } },
"server.js": { file: { contents: "..." } }
}
}
};
await enjin.mount(templates, "vite-vanilla");Events
Listen to various events during operation:
enjin.on('connect', () => {
console.log('Connected to VPS');
});
enjin.on('disconnect', () => {
console.log('Disconnected from VPS');
});
enjin.on('error', (error) => {
console.error('Error:', error.message);
});
enjin.on('reconnecting', (attempt) => {
console.log(`Reconnection attempt ${attempt}`);
});
enjin.on('upload-progress', (progress) => {
console.log(`${progress.file}: ${progress.percentage}%`);
});
enjin.on('command-output', (data) => {
process.stdout.write(data);
});Examples
Vite React Project
const enjin = new KumoEnjin({ /* config */ });
await enjin.connect();
await enjin.mount({
directory: {
"package.json": {
file: { contents: JSON.stringify({
name: "vite-react-app",
scripts: { dev: "vite --host 0.0.0.0" },
dependencies: { vite: "^4.0.0", react: "^18.0.0" }
}, null, 2) }
},
"index.html": {
file: { contents: `<!DOCTYPE html>
<html><head><title>Vite React</title></head>
<body><div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body></html>` }
},
"src": {
directory: {
"main.jsx": {
file: { contents: `import React from 'react'
import ReactDOM from 'react-dom/client'
ReactDOM.createRoot(document.getElementById('root')).render(<h1>Hello Vite!</h1>)` }
}
}
}
}
});
await enjin.run("npm install");
const { url } = await enjin.start("npm run dev", 5173);
console.log(`React app running at: ${url}`);Security Considerations
- Use SSH keys instead of passwords for production
- Commands are sanitized to prevent basic injection attacks
- Each session uses isolated temporary directories
- Automatic cleanup prevents file accumulation
- Connection timeouts prevent hanging connections
Error Handling
try {
await enjin.connect();
await enjin.mount(template);
const { url } = await enjin.start();
console.log(`Server running at: ${url}`);
} catch (error) {
console.error('Failed to start server:', error.message);
} finally {
await enjin.stopDevServer(); // Always cleanup
}Requirements
- Node.js >= 16.0.0
- SSH access to your VPS
- VPS with required runtime environments (Node.js, Python, etc.)
License
MIT
