Files
hyperframes/packages/cli/src/utils/hostAnswers.ts
T
Miguel Ángel 693c385508 fix(cli): commands exit right away even when the network or DNS is broken (#4604)
* fix(cli): commands exit without waiting on update checks or telemetry

The update and skills checks run in a detached child that refreshes the
caches for the next run; the parent only reads the caches. finalizeCli no
longer awaits the telemetry flush: the exit handler flushSync() delivers
what is queued. The events beacon, feedback and figma error paths stop
awaiting flush() too.

* fix(cli): retry a failed background check at most once an hour

Before starting the background worker, the CLI stamps a per-check attempt
time and skips a check it attempted within the hour, so a dead network no
longer starts a worker on every command. The stale-pin notice writes onto a
fresh read, detached spawns set windowsHide, and a test ties the worker path
to its build entry.

* fix(cli): a failed-check stamp dated in the future no longer silences update checks
2026-09-28 02:22:12 +00:00

28 lines
1.1 KiB
TypeScript

import { promises as dns } from "node:dns";
const PROBE_TIMEOUT_MS = 1000;
function fetchGoesThroughEnvProxy(): boolean {
if (!(process.env["HTTPS_PROXY"] ?? process.env["https_proxy"])?.trim()) return false;
const flags = [...process.execArgv, ...(process.env["NODE_OPTIONS"]?.split(/\s+/u) ?? [])];
return process.env["NODE_USE_ENV_PROXY"] === "1" || flags.includes("--use-env-proxy");
}
/**
* Whether DNS answers for `host` via c-ares, one short try per nameserver. The system lookup
* `fetch` makes cannot be aborted and holds even `process.exit`, so background requests ask this first.
*/
export async function hostAnswers(host: string): Promise<boolean> {
if (fetchGoesThroughEnvProxy()) return true;
try {
const resolver = new dns.Resolver({ timeout: PROBE_TIMEOUT_MS, tries: 1 });
const results = await Promise.allSettled([resolver.resolve4(host), resolver.resolve6(host)]);
const anyFamilyTimedOut = results.some(
(r) => r.status === "rejected" && (r.reason as NodeJS.ErrnoException).code === "ETIMEOUT",
);
return !anyFamilyTimedOut && results.some((r) => r.status === "fulfilled");
} catch {
return false;
}
}