@lunora/cli
Version:
The Lunora CLI: init, dev, deploy, codegen, run, reset, and migrate commands
43 lines (40 loc) • 1.49 kB
JavaScript
import { spawn } from 'node:child_process';
import { platform } from 'node:os';
import { LunoraError } from '@lunora/errors';
const platformCommand = () => {
const os = platform();
if (os === "darwin") {
return { args: [], command: "open" };
}
if (os === "win32") {
return { args: ["/c", "start", ""], command: "cmd" };
}
return { args: [], command: "xdg-open" };
};
const escapeForCmd = (url) => url.replaceAll("%", "%25").replaceAll("&", "%26").replaceAll("|", "%7C").replaceAll("^", "%5E").replaceAll("<", "%3C").replaceAll(">", "%3E").replaceAll("(", "%28").replaceAll(")", "%29").replaceAll('"', "%22").replaceAll("!", "%21");
const platformOpener = (url) => new Promise((resolve, reject) => {
const { args, command } = platformCommand();
const safeUrl = platform() === "win32" ? escapeForCmd(url) : url;
const child = spawn(command, [...args, safeUrl], { detached: true, stdio: "ignore" });
child.once("error", (error) => {
reject(error);
});
child.once("spawn", () => {
child.unref();
resolve();
});
});
const openUrl = async (url, options = {}) => {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new LunoraError("INTERNAL", `Invalid URL: ${url}`);
}
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
throw new LunoraError("INTERNAL", `Refusing to open non-http(s) URL: ${url}`);
}
const opener = options.opener ?? platformOpener;
await opener(url);
};
export { openUrl as o };