refactor: lint cleanups and helpers

This commit is contained in:
Peter Steinberger
2025-12-23 00:28:40 +00:00
parent f5837dff9c
commit 918cbdcf03
39 changed files with 679 additions and 338 deletions

View File

@@ -1,6 +1,7 @@
import { createServer } from "node:net";
import { afterEach, describe, expect, test } from "vitest";
import { WebSocketServer } from "ws";
import { rawDataToString } from "../infra/ws.js";
import { GatewayClient } from "./client.js";
// Find a free localhost port for ad-hoc WS servers.
@@ -30,7 +31,7 @@ describe("GatewayClient", () => {
wss.on("connection", (socket) => {
socket.once("message", (data) => {
const first = JSON.parse(String(data)) as { id?: string };
const first = JSON.parse(rawDataToString(data)) as { id?: string };
const id = first.id ?? "connect";
// Respond with tiny tick interval to trigger watchdog quickly.
const helloOk = {

View File

@@ -1,5 +1,6 @@
import { randomUUID } from "node:crypto";
import { WebSocket } from "ws";
import { rawDataToString } from "../infra/ws.js";
import { logDebug, logError } from "../logger.js";
import {
type ConnectParams,
@@ -57,14 +58,15 @@ export class GatewayClient {
this.ws = new WebSocket(url, { maxPayload: 25 * 1024 * 1024 });
this.ws.on("open", () => this.sendConnect());
this.ws.on("message", (data) => this.handleMessage(data.toString()));
this.ws.on("message", (data) => this.handleMessage(rawDataToString(data)));
this.ws.on("close", (code, reason) => {
const reasonText = rawDataToString(reason);
this.ws = null;
this.flushPendingErrors(
new Error(`gateway closed (${code}): ${reason.toString()}`),
new Error(`gateway closed (${code}): ${reasonText}`),
);
this.scheduleReconnect();
this.opts.onClose?.(code, reason.toString());
this.opts.onClose?.(code, reasonText);
});
this.ws.on("error", (err) => {
logDebug(`gateway client error: ${String(err)}`);

View File

@@ -10,6 +10,7 @@ import { readConfigFileSnapshot, writeConfigFile } from "../config/config.js";
import { emitAgentEvent } from "../infra/agent-events.js";
import { GatewayLockError } from "../infra/gateway-lock.js";
import { emitHeartbeatEvent } from "../infra/heartbeat-events.js";
import { rawDataToString } from "../infra/ws.js";
import { PROTOCOL_VERSION } from "./protocol/index.js";
import {
__resetModelCatalogCacheForTest,
@@ -298,7 +299,7 @@ function onceMessage<T = unknown>(
reject(new Error(`closed ${code}: ${reason.toString()}`));
};
const handler = (data: WebSocket.RawData) => {
const obj = JSON.parse(String(data));
const obj = JSON.parse(rawDataToString(data));
if (filter(obj)) {
clearTimeout(timer);
ws.off("message", handler);
@@ -678,7 +679,7 @@ describe("gateway server", () => {
expect(res1.ok).toBe(true);
const req1 = (res1.payload as { request?: { requestId?: unknown } } | null)
?.request;
const requestId = String(req1?.requestId ?? "");
const requestId = typeof req1?.requestId === "string" ? req1.requestId : "";
expect(requestId.length).toBeGreaterThan(0);
const evt1 = await requestedP;
@@ -731,10 +732,10 @@ describe("gateway server", () => {
payload?: unknown;
}>(ws, (o) => o.type === "res" && o.id === "pair-approve-1");
expect(approveRes.ok).toBe(true);
const token = String(
(approveRes.payload as { node?: { token?: unknown } } | null)?.node
?.token ?? "",
);
const tokenValue = (
approveRes.payload as { node?: { token?: unknown } } | null
)?.node?.token;
const token = typeof tokenValue === "string" ? tokenValue : "";
expect(token.length).toBeGreaterThan(0);
const evt2 = await resolvedP;
@@ -1235,7 +1236,8 @@ describe("gateway server", () => {
payload?: unknown;
}>(ws, (o) => o.type === "res" && o.id === "cron-add-log-1");
expect(addRes.ok).toBe(true);
const jobId = String((addRes.payload as { id?: unknown } | null)?.id ?? "");
const jobIdValue = (addRes.payload as { id?: unknown } | null)?.id;
const jobId = typeof jobIdValue === "string" ? jobIdValue : "";
expect(jobId.length > 0).toBe(true);
ws.send(
@@ -1345,7 +1347,8 @@ describe("gateway server", () => {
payload?: unknown;
}>(ws, (o) => o.type === "res" && o.id === "cron-add-log-2");
expect(addRes.ok).toBe(true);
const jobId = String((addRes.payload as { id?: unknown } | null)?.id ?? "");
const jobIdValue = (addRes.payload as { id?: unknown } | null)?.id;
const jobId = typeof jobIdValue === "string" ? jobIdValue : "";
expect(jobId.length > 0).toBe(true);
ws.send(
@@ -1451,7 +1454,11 @@ describe("gateway server", () => {
| { enabled?: unknown; storePath?: unknown }
| undefined;
expect(statusPayload?.enabled).toBe(true);
expect(String(statusPayload?.storePath ?? "")).toContain("jobs.json");
const storePath =
typeof statusPayload?.storePath === "string"
? statusPayload.storePath
: "";
expect(storePath).toContain("jobs.json");
const atMs = Date.now() + 80;
ws.send(
@@ -1475,9 +1482,8 @@ describe("gateway server", () => {
payload?: unknown;
}>(ws, (o) => o.type === "res" && o.id === "cron-add-auto-1");
expect(addRes.ok).toBe(true);
const jobId = String(
(addRes.payload as { id?: unknown } | null)?.id ?? "",
);
const jobIdValue = (addRes.payload as { id?: unknown } | null)?.id;
const jobId = typeof jobIdValue === "string" ? jobIdValue : "";
expect(jobId.length > 0).toBe(true);
const finishedEvt = await onceMessage<{

View File

@@ -105,6 +105,7 @@ import {
WIDE_AREA_DISCOVERY_DOMAIN,
writeWideAreaBridgeZone,
} from "../infra/widearea-dns.js";
import { rawDataToString } from "../infra/ws.js";
import {
createSubsystemLogger,
getChildLogger,
@@ -1144,10 +1145,18 @@ const wsInflightSince = new Map<string, number>();
function formatError(err: unknown): string {
if (err instanceof Error) return err.message;
if (typeof err === "string") return err;
const status = (err as { status?: unknown })?.status;
const code = (err as { code?: unknown })?.code;
if (status || code)
return `status=${status ?? "unknown"} code=${code ?? "unknown"}`;
const statusValue = (err as { status?: unknown })?.status;
const codeValue = (err as { code?: unknown })?.code;
const statusText =
typeof statusValue === "string" || typeof statusValue === "number"
? String(statusValue)
: undefined;
const codeText =
typeof codeValue === "string" || typeof codeValue === "number"
? String(codeValue)
: undefined;
if (statusText || codeText)
return `status=${statusText ?? "unknown"} code=${codeText ?? "unknown"}`;
return JSON.stringify(err, null, 2);
}
@@ -1161,8 +1170,7 @@ async function refreshHealthSnapshot(_opts?: { probe?: boolean }) {
broadcastHealthUpdate(snap);
}
return snap;
})();
healthRefresh.finally(() => {
})().finally(() => {
healthRefresh = null;
});
}
@@ -1183,13 +1191,17 @@ export async function startGatewayServer(
}
const controlUiEnabled =
opts.controlUiEnabled ?? cfgAtStart.gateway?.controlUi?.enabled ?? true;
const authBase = cfgAtStart.gateway?.auth ?? {};
const authOverrides = opts.auth ?? {};
const authConfig = {
...(cfgAtStart.gateway?.auth ?? {}),
...(opts.auth ?? {}),
...authBase,
...authOverrides,
};
const tailscaleBase = cfgAtStart.gateway?.tailscale ?? {};
const tailscaleOverrides = opts.tailscale ?? {};
const tailscaleConfig = {
...(cfgAtStart.gateway?.tailscale ?? {}),
...(opts.tailscale ?? {}),
...tailscaleBase,
...tailscaleOverrides,
};
const tailscaleMode = tailscaleConfig.mode ?? "off";
const token = getGatewayToken();
@@ -1849,8 +1861,17 @@ export async function startGatewayServer(
},
};
}
const raw = String((params as { raw?: unknown }).raw ?? "");
const parsedRes = parseConfigJson5(raw);
const rawValue = (params as { raw?: unknown }).raw;
if (typeof rawValue !== "string") {
return {
ok: false,
error: {
code: ErrorCodes.INVALID_REQUEST,
message: "invalid config.set params: raw (string) required",
},
};
}
const parsedRes = parseConfigJson5(rawValue);
if (!parsedRes.ok) {
return {
ok: false,
@@ -2949,7 +2970,9 @@ export async function startGatewayServer(
const payload = {
...base,
state: "error",
errorMessage: evt.data.error ? String(evt.data.error) : undefined,
errorMessage: evt.data.error
? formatForLog(evt.data.error)
: undefined,
};
broadcast("chat", payload);
bridgeSendToSession(sessionKey, "chat", payload);
@@ -3061,7 +3084,7 @@ export async function startGatewayServer(
socket.on("message", async (data) => {
if (closed) return;
const text = data.toString();
const text = rawDataToString(data);
try {
const parsed = JSON.parse(text);
if (!client) {
@@ -4034,8 +4057,19 @@ export async function startGatewayServer(
);
break;
}
const raw = String((params as { raw?: unknown }).raw ?? "");
const parsedRes = parseConfigJson5(raw);
const rawValue = (params as { raw?: unknown }).raw;
if (typeof rawValue !== "string") {
respond(
false,
undefined,
errorShape(
ErrorCodes.INVALID_REQUEST,
"invalid config.set params: raw (string) required",
),
);
break;
}
const parsedRes = parseConfigJson5(rawValue);
if (!parsedRes.ok) {
respond(
false,
@@ -4147,8 +4181,10 @@ export async function startGatewayServer(
env?: Record<string, string>;
};
const cfg = loadConfig();
const skills = { ...(cfg.skills ?? {}) };
const current = { ...(skills[p.skillKey] ?? {}) };
const skills = cfg.skills ? { ...cfg.skills } : {};
const current = skills[p.skillKey]
? { ...skills[p.skillKey] }
: {};
if (typeof p.enabled === "boolean") {
current.enabled = p.enabled;
}
@@ -4158,11 +4194,11 @@ export async function startGatewayServer(
else delete current.apiKey;
}
if (p.env && typeof p.env === "object") {
const nextEnv = { ...(current.env ?? {}) };
const nextEnv = current.env ? { ...current.env } : {};
for (const [key, value] of Object.entries(p.env)) {
const trimmedKey = key.trim();
if (!trimmedKey) continue;
const trimmedVal = String(value ?? "").trim();
const trimmedVal = value.trim();
if (!trimmedVal) delete nextEnv[trimmedKey];
else nextEnv[trimmedKey] = trimmedVal;
}
@@ -4541,7 +4577,8 @@ export async function startGatewayServer(
}
case "system-event": {
const params = (req.params ?? {}) as Record<string, unknown>;
const text = String(params.text ?? "").trim();
const text =
typeof params.text === "string" ? params.text.trim() : "";
if (!text) {
respond(
false,