refactor: centralize isPlainObject, isRecord, isErrno, isLoopbackHost utilities (#12926)

This commit is contained in:
max
2026-02-09 17:02:55 -08:00
committed by GitHub
parent 70f9edeec7
commit 8d75a496bf
37 changed files with 97 additions and 226 deletions

View File

@@ -1,3 +1,5 @@
import { isLoopbackHost } from "../gateway/net.js";
type HostSource = string | null | undefined;
type CanvasHostUrlParams = {
@@ -9,23 +11,6 @@ type CanvasHostUrlParams = {
scheme?: "http" | "https";
};
const isLoopbackHost = (value: string) => {
const normalized = value.trim().toLowerCase();
if (!normalized) {
return false;
}
if (normalized === "localhost") {
return true;
}
if (normalized === "::1") {
return true;
}
if (normalized === "0.0.0.0" || normalized === "::") {
return true;
}
return normalized.startsWith("127.");
};
const normalizeHost = (value: HostSource, rejectLoopback: boolean) => {
if (!value) {
return "";

View File

@@ -12,6 +12,20 @@ export function extractErrorCode(err: unknown): string | undefined {
return undefined;
}
/**
* Type guard for NodeJS.ErrnoException (any error with a `code` property).
*/
export function isErrno(err: unknown): err is NodeJS.ErrnoException {
return Boolean(err && typeof err === "object" && "code" in err);
}
/**
* Check if an error has a specific errno code.
*/
export function hasErrnoCode(err: unknown, code: string): boolean {
return isErrno(err) && err.code === code;
}
export function formatErrorMessage(err: unknown): string {
if (err instanceof Error) {
return err.message || err.name || "Error";

View File

@@ -1,6 +1,7 @@
import net from "node:net";
import type { PortListener, PortUsage, PortUsageStatus } from "./ports-types.js";
import { runCommandWithTimeout } from "../process/exec.js";
import { isErrno } from "./errors.js";
import { buildPortHints } from "./ports-format.js";
import { resolveLsofCommand } from "./ports-lsof.js";
@@ -11,10 +12,6 @@ type CommandResult = {
error?: string;
};
function isErrno(err: unknown): err is NodeJS.ErrnoException {
return Boolean(err && typeof err === "object" && "code" in err);
}
async function runCommandSafe(argv: string[], timeoutMs = 5_000): Promise<CommandResult> {
try {
const res = await runCommandWithTimeout(argv, { timeoutMs });

View File

@@ -4,6 +4,7 @@ import type { PortListener, PortListenerKind, PortUsage, PortUsageStatus } from
import { danger, info, shouldLogVerbose, warn } from "../globals.js";
import { logDebug } from "../logger.js";
import { defaultRuntime } from "../runtime.js";
import { isErrno } from "./errors.js";
import { formatPortDiagnostics } from "./ports-format.js";
import { inspectPortUsage } from "./ports-inspect.js";
@@ -19,10 +20,6 @@ class PortInUseError extends Error {
}
}
function isErrno(err: unknown): err is NodeJS.ErrnoException {
return Boolean(err && typeof err === "object" && "code" in err);
}
export async function describePortOwner(port: number): Promise<string | undefined> {
const diagnostics = await inspectPortUsage(port);
if (diagnostics.listeners.length === 0) {

View File

@@ -1,4 +1,5 @@
import type { ProviderUsageSnapshot, UsageWindow } from "./provider-usage.types.js";
import { isRecord } from "../utils.js";
import { fetchJson } from "./provider-usage.fetch.shared.js";
import { clampPercent, PROVIDER_LABELS } from "./provider-usage.shared.js";
@@ -148,10 +149,6 @@ const WINDOW_MINUTE_KEYS = [
"minutes",
] as const;
function isRecord(value: unknown): value is Record<string, unknown> {
return Boolean(value && typeof value === "object" && !Array.isArray(value));
}
function pickNumber(record: Record<string, unknown>, keys: readonly string[]): number | undefined {
for (const key of keys) {
const value = record[key];

View File

@@ -1,5 +1,6 @@
import { spawn } from "node:child_process";
import net from "node:net";
import { isErrno } from "./errors.js";
import { ensurePortAvailable } from "./ports.js";
export type SshParsedTarget = {
@@ -17,10 +18,6 @@ export type SshTunnel = {
stop: () => Promise<void>;
};
function isErrno(err: unknown): err is NodeJS.ErrnoException {
return Boolean(err && typeof err === "object" && "code" in err);
}
export function parseSshTarget(raw: string): SshParsedTarget | null {
const trimmed = raw.trim().replace(/^ssh\s+/, "");
if (!trimmed) {