fix(cli): use rundll32 instead of cmd.exe for Windows browser fallback in dashboard command (#7844)

* fix(cli): use rundll32 instead of cmd.exe for Windows browser fallback in dashboard command

Extract resolveOpenCommand(platform, url) as an exported pure function so tests import the actual production code instead of duplicating logic.

The openFallback function in bin/cli/commands/dashboard.mjs used cmd /c start to open the dashboard URL on Windows, spawning an unnecessary cmd.exe process. Replaces with rundll32 url.dll,FileProtocolHandler which opens the URL directly through the Windows shell handler API without any shell wrapper.

Tests: 5 tests importing the actual resolveOpenCommand function, covering all platform branches (darwin, win32, linux) and URL pass-through. Changelog fragment included.

* chore: rename changelog fragment 7842->7844 to match actual PR number

---------

Co-authored-by: tientien17 <tientien17@users.noreply.github.com>
This commit is contained in:
ToastedPatatas
2026-07-21 02:56:08 +08:00
committed by GitHub
parent ee3546a6ce
commit 7d82b72def
3 changed files with 50 additions and 14 deletions

View File

@@ -49,22 +49,22 @@ export async function runDashboardCommand(opts = {}) {
return 0;
}
/**
* Resolve the command and args to open a URL in the default browser
* for a given platform. Exported for testing — callers should use openFallback().
* @param {"darwin"|"win32"|string} platform
* @param {string} url
* @returns {{ cmd: string, args: string[] }}
*/
export function resolveOpenCommand(platform, url) {
if (platform === "darwin") return { cmd: "open", args: [url] };
if (platform === "win32") return { cmd: "rundll32", args: ["url.dll,FileProtocolHandler", url] };
return { cmd: "xdg-open", args: [url] };
}
function openFallback(url) {
return new Promise((resolve) => {
const { platform } = process;
let cmd, args;
if (platform === "darwin") {
cmd = "open";
args = [url];
} else if (platform === "win32") {
cmd = "cmd";
args = ["/c", "start", "", url];
} else {
cmd = "xdg-open";
args = [url];
}
const { cmd, args } = resolveOpenCommand(process.platform, url);
execFile(cmd, args, { stdio: "ignore" }, () => resolve());
});
}

View File

@@ -0,0 +1 @@
- **fix(cli):** Windows `omniroute dashboard` browser fallback uses `rundll32` instead of `cmd.exe` to open the dashboard URL, avoiding an unnecessary shell spawn ([#7844](https://github.com/diegosouzapw/OmniRoute/pull/7842))

View File

@@ -0,0 +1,35 @@
import test from "node:test";
import assert from "node:assert/strict";
import { resolveOpenCommand } from "../../bin/cli/commands/dashboard.mjs";
test("openFallback: darwin uses 'open' command", () => {
const { cmd, args } = resolveOpenCommand("darwin", "http://localhost:20128");
assert.equal(cmd, "open");
assert.deepEqual(args, ["http://localhost:20128"]);
});
test("openFallback: win32 uses 'rundll32 url.dll,FileProtocolHandler' instead of cmd.exe", () => {
const { cmd, args } = resolveOpenCommand("win32", "http://localhost:20128");
assert.equal(cmd, "rundll32");
assert.deepEqual(args, ["url.dll,FileProtocolHandler", "http://localhost:20128"]);
assert.notEqual(cmd, "cmd");
});
test("openFallback: linux/other uses 'xdg-open' command", () => {
const { cmd, args } = resolveOpenCommand("linux", "http://localhost:20128");
assert.equal(cmd, "xdg-open");
assert.deepEqual(args, ["http://localhost:20128"]);
});
test("openFallback: unknown platform falls back to xdg-open", () => {
const { cmd, args } = resolveOpenCommand("aix", "http://localhost:20128");
assert.equal(cmd, "xdg-open");
assert.deepEqual(args, ["http://localhost:20128"]);
});
test("openFallback: URL with special characters is passed through verbatim", () => {
const url = "http://localhost:20128/dashboard?q=test&filter=a+b";
const { cmd, args } = resolveOpenCommand("win32", url);
assert.equal(cmd, "rundll32");
assert.equal(args[1], url);
});