mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
Release v3.8.32 (#4418)
Release v3.8.32 — see CHANGELOG.md [3.8.32] for the full list. Merged via --admin over documented non-blocking checks: CodeQL alerts ratchet (#665 fixed by #4457/#4462, auto-closes on main rescan), Integration Tests (env-flaky batch-upstream), SonarCloud/SonarQube (advisory new-code).
This commit is contained in:
committed by
GitHub
parent
d0396c200d
commit
bfaf459f3c
@@ -9,7 +9,15 @@ function authLabel(c) {
|
||||
return "✗";
|
||||
}
|
||||
|
||||
async function confirm(msg) {
|
||||
export async function confirm(msg) {
|
||||
// Non-interactive stdin (pipe, CI, EOF) cannot answer a [y/N] prompt. Asking
|
||||
// anyway leaves the readline question pending forever — Node then warns about an
|
||||
// "unsettled top-level await" at exit. Decline cleanly instead and point at the
|
||||
// non-interactive escape hatch so scripted callers fail safe rather than hang.
|
||||
if (!process.stdin.isTTY) {
|
||||
process.stderr.write(`${msg} [y/N] (non-interactive stdin — declined; pass --yes to confirm)\n`);
|
||||
return false;
|
||||
}
|
||||
const readline = await import("node:readline");
|
||||
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
||||
const answer = await new Promise((r) => rl.question(`${msg} [y/N] `, r));
|
||||
@@ -26,6 +34,7 @@ function maskKey(k) {
|
||||
export function registerContexts(program) {
|
||||
const ctx = program
|
||||
.command("contexts")
|
||||
.alias("context") // singular alias — docs/connect output historically said `context current`
|
||||
.description(t("config.contexts.description") || "Manage server contexts/profiles");
|
||||
|
||||
ctx
|
||||
|
||||
@@ -25,9 +25,13 @@ export async function getCurrentVersion() {
|
||||
}
|
||||
}
|
||||
|
||||
async function getLatestVersion() {
|
||||
// `--prefer-online` forces npm to revalidate its HTTP cache against the registry.
|
||||
// Without it `npm view` can return a stale cached version (e.g. report 3.8.30 as
|
||||
// "latest" after 3.8.31 was published), so the updater told users on an old build
|
||||
// they were already on the latest version (#4376). `execFn` is injectable for tests.
|
||||
export async function getLatestVersion(execFn = execFileAsync) {
|
||||
try {
|
||||
const { stdout } = await execFileAsync("npm", ["view", "omniroute", "version"], {
|
||||
const { stdout } = await execFn("npm", ["view", "omniroute", "version", "--prefer-online"], {
|
||||
timeout: 15000,
|
||||
});
|
||||
return stdout.trim();
|
||||
|
||||
@@ -6,20 +6,43 @@ export function createPrompt() {
|
||||
output: process.stdout,
|
||||
});
|
||||
|
||||
// Non-interactive stdin (pipe, CI, EOF via `< /dev/null`) cannot answer an
|
||||
// interactive prompt. Without a guard, `rl.question` never fires its callback —
|
||||
// the await stays pending and Node warns about an "unsettled top-level await" at
|
||||
// exit. Resolving on the readline `close` event (which fires on stdin EOF)
|
||||
// returns the default/empty instead of hanging. A genuinely piped line still
|
||||
// arrives via the question callback first, so `echo value | omniroute …` keeps
|
||||
// working — only the no-input EOF case falls back.
|
||||
function ask(question, defaultValue = "") {
|
||||
const suffix = defaultValue ? ` (${defaultValue})` : "";
|
||||
return new Promise((resolve) => {
|
||||
let settled = false;
|
||||
const done = (v) => {
|
||||
if (!settled) {
|
||||
settled = true;
|
||||
resolve(v);
|
||||
}
|
||||
};
|
||||
rl.once("close", () => done(defaultValue));
|
||||
rl.question(`${question}${suffix}: `, (answer) => {
|
||||
const trimmed = answer.trim();
|
||||
resolve(trimmed || defaultValue);
|
||||
done(trimmed || defaultValue);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function askSecret(question) {
|
||||
return new Promise((resolve) => {
|
||||
let prompted = false;
|
||||
let settled = false;
|
||||
const saved = rl._writeToOutput.bind(rl);
|
||||
const done = (v) => {
|
||||
if (!settled) {
|
||||
settled = true;
|
||||
rl._writeToOutput = saved;
|
||||
resolve(v);
|
||||
}
|
||||
};
|
||||
let prompted = false;
|
||||
rl._writeToOutput = function (str) {
|
||||
if (!prompted) {
|
||||
rl.output.write(str);
|
||||
@@ -29,9 +52,9 @@ export function createPrompt() {
|
||||
// Suppress character echo; allow only newlines through
|
||||
if (str === "\r\n" || str === "\n" || str === "\r") rl.output.write("\n");
|
||||
};
|
||||
rl.once("close", () => done("")); // non-interactive EOF → empty secret, no hang
|
||||
rl.question(`${question}: `, (answer) => {
|
||||
rl._writeToOutput = saved;
|
||||
resolve(answer.trim());
|
||||
done(answer.trim());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user