mongoku
Version:
[](https://github.com/huggingface/Mongoku/actions/workflows/ci.yml)
161 lines (134 loc) • 4.99 kB
text/typescript
import chalk from "chalk";
import { spawn, SpawnOptions } from "child_process";
import { Command } from "commander";
import { readFileSync } from "fs";
import { dirname, join } from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Read version from package.json (go up one level if in dist directory)
const rootDir = __dirname.endsWith("dist") ? dirname(__dirname) : __dirname;
const packageJsonPath = join(rootDir, "package.json");
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
const version = packageJson.version;
const program = new Command();
// generated by figlet.textSync('Mongoku', { horizontalLayout: 'full' }))
// __ __ _
// | \/ | ___ _ __ __ _ ___ | | __ _ _
// | |\/| | / _ \ | '_ \ / _` | / _ \ | |/ / | | | |
// | | | | | (_) | | | | | | (_| | | (_) | | < | |_| |
// |_| |_| \___/ |_| |_| \__, | \___/ |_|\_\ \__,_|
// |___/
const asciiArt = [
"__ __ _ ",
"| \\/ | ___ _ __ __ _ ___ | | __ _ _ ",
"| |\\/| | / _ \\ | '_ \\ / _` | / _ \\ | |/ / | | | |",
"| | | | | (_) | | | | | | (_| | | (_) | | < | |_| |",
"|_| |_| \\___/ |_| |_| \\__, | \\___/ |_|\\_\\ \\__,_|",
" |___/ ",
].join("\n");
program.name("mongoku").description("MongoDB client for the web").version(version);
// Custom error handler for better error messages
program.configureOutput({
outputError: (str, write) => {
// Check for common mistakes
if (str.includes("too many arguments")) {
const args = process.argv.slice(2);
if (args.includes("pm2")) {
write(chalk.red("❌ Error: Did you mean '--pm2' instead of 'pm2'?\n"));
return;
}
}
write(chalk.red(str));
},
});
// Start action handler (shared between default and explicit 'start' command)
async function startAction(options: { pm2?: boolean; port?: string; readonly?: boolean }) {
console.log(chalk.cyan(asciiArt));
const port = options.port || process.env.MONGOKU_SERVER_PORT || "3100";
process.env.MONGOKU_SERVER_PORT = port;
if (!process.env.MONGOKU_SERVER_ORIGIN) {
process.env.MONGOKU_SERVER_ORIGIN = `http://localhost:${port}`;
}
// Suppress the default "Listening on..." log since we show our own message
process.env.MONGOKU_SUPPRESS_STARTUP_LOG = "true";
if (!process.env.MONGOKU_SERVER_BODY_SIZE_LIMIT) {
process.env.MONGOKU_SERVER_BODY_SIZE_LIMIT = "Infinity";
}
// Set read-only mode if specified
if (options.readonly) {
process.env.MONGOKU_READ_ONLY_MODE = "true";
console.log(chalk.yellow("🔒 Read-only mode enabled"));
}
if (options.pm2) {
console.log(chalk.green(`🚀 Starting Mongoku with PM2 on port ${port}...`));
runCommand("pm2", ["--name", "mongoku", "start", "ecosystem.config.js", "--update-env"], {
stdio: "inherit",
cwd: rootDir,
});
} else {
console.log(chalk.green(`🚀 Starting Mongoku on port ${port}...`));
console.log(chalk.cyan(`📊 Open http://localhost:${port} in your browser`));
runCommand("node", ["build"], { stdio: "inherit", cwd: rootDir });
}
}
program
.command("stop")
.description("Stop the Mongoku server running with PM2")
.action(() => {
runCommand("pm2", ["stop", "mongoku"], { stdio: "inherit" });
});
program
.command("start")
.description("Start the Mongoku server")
.option("--pm2", "Run with PM2")
.option("-p, --port <port>", "Port to run on", "3100")
.option("--readonly", "Enable read-only mode (prevents modifications)")
.allowExcessArguments(false)
.action(startAction);
program
.command("help")
.description("Show help")
.action(() => {
program.outputHelp();
});
// Default action (start the server)
program
.option("--pm2", "Run with PM2")
.option("-p, --port <port>", "Port to run on", "3100")
.option("--readonly", "Enable read-only mode (prevents modifications)")
.allowExcessArguments(false)
.action(startAction);
function runCommand(command: string, args: string[], options: SpawnOptions = {}): Promise<void> {
return new Promise((resolve, reject) => {
const childProcess = spawn(command, args, {
...options,
env: { ...process.env },
});
if (!options.detached && options.stdio !== "inherit") {
childProcess.stdout?.on("data", (data) => {
console.log(data.toString());
});
childProcess.stderr?.on("data", (data) => {
console.error(data.toString());
});
}
childProcess.on("error", (error) => {
console.error(chalk.red(`Error: ${error.message}`));
reject(error);
});
childProcess.on("close", (code) => {
if (code !== 0 && !options.detached) {
reject(new Error(`Command failed with exit code ${code}`));
} else {
resolve();
}
});
if (options.detached) {
childProcess.unref();
resolve();
}
});
}
program.parse(process.argv);