From d0337a18b6473b3ca165b886267f07e4cb481bf2 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 13 Mar 2026 22:08:54 +0000 Subject: [PATCH] fix: clear typecheck backlog --- .../src/monitor.webhook-auth.test.ts | 13 +++--- extensions/feishu/src/probe.test.ts | 2 +- .../matrix/src/matrix/monitor/events.test.ts | 42 +++++++++++++------ .../nostr/src/nostr-profile-http.test.ts | 14 +++---- .../synology-chat/src/webhook-handler.test.ts | 3 +- extensions/zalo/src/monitor.ts | 2 +- extensions/zalo/src/send.ts | 16 ++----- .../onboard-non-interactive.gateway.test.ts | 15 +++++-- src/node-host/invoke-system-run.ts | 1 + src/slack/monitor/events/messages.test.ts | 1 - 10 files changed, 63 insertions(+), 46 deletions(-) diff --git a/extensions/bluebubbles/src/monitor.webhook-auth.test.ts b/extensions/bluebubbles/src/monitor.webhook-auth.test.ts index b72b95dc4cc..f6826ac510b 100644 --- a/extensions/bluebubbles/src/monitor.webhook-auth.test.ts +++ b/extensions/bluebubbles/src/monitor.webhook-auth.test.ts @@ -328,13 +328,14 @@ describe("BlueBubbles webhook monitor", () => { } function createHangingWebhookRequest(url = "/bluebubbles-webhook?password=test-password") { - const req = new EventEmitter() as IncomingMessage & { destroy: ReturnType }; + const req = new EventEmitter() as IncomingMessage; + const destroyMock = vi.fn(); req.method = "POST"; req.url = url; req.headers = {}; - req.destroy = vi.fn(); + req.destroy = destroyMock as unknown as IncomingMessage["destroy"]; setRequestRemoteAddress(req, "127.0.0.1"); - return req; + return { req, destroyMock }; } function registerWebhookTargets( @@ -415,7 +416,7 @@ describe("BlueBubbles webhook monitor", () => { setupWebhookTarget(); // Create a request that never sends data or ends (simulates slow-loris) - const req = createHangingWebhookRequest(); + const { req, destroyMock } = createHangingWebhookRequest(); const res = createMockResponse(); @@ -427,7 +428,7 @@ describe("BlueBubbles webhook monitor", () => { const handled = await handledPromise; expect(handled).toBe(true); expect(res.statusCode).toBe(408); - expect(req.destroy).toHaveBeenCalled(); + expect(destroyMock).toHaveBeenCalled(); } finally { vi.useRealTimers(); } @@ -436,7 +437,7 @@ describe("BlueBubbles webhook monitor", () => { it("rejects unauthorized requests before reading the body", async () => { const account = createMockAccount({ password: "secret-token" }); setupWebhookTarget({ account }); - const req = createHangingWebhookRequest("/bluebubbles-webhook?password=wrong-token"); + const { req } = createHangingWebhookRequest("/bluebubbles-webhook?password=wrong-token"); const onSpy = vi.spyOn(req, "on"); await expectWebhookStatus(req, 401); expect(onSpy).not.toHaveBeenCalledWith("data", expect.any(Function)); diff --git a/extensions/feishu/src/probe.test.ts b/extensions/feishu/src/probe.test.ts index 328c83f658a..bfc270a4459 100644 --- a/extensions/feishu/src/probe.test.ts +++ b/extensions/feishu/src/probe.test.ts @@ -40,7 +40,7 @@ function setupSuccessClient() { async function expectDefaultSuccessResult( creds = DEFAULT_CREDS, - expected = DEFAULT_SUCCESS_RESULT, + expected: Awaited> = DEFAULT_SUCCESS_RESULT, ) { const result = await probeFeishu(creds); expect(result).toEqual(expected); diff --git a/extensions/matrix/src/matrix/monitor/events.test.ts b/extensions/matrix/src/matrix/monitor/events.test.ts index 3c08a0230d1..6dac0db59fc 100644 --- a/extensions/matrix/src/matrix/monitor/events.test.ts +++ b/extensions/matrix/src/matrix/monitor/events.test.ts @@ -14,6 +14,17 @@ vi.mock("../send.js", () => ({ describe("registerMatrixMonitorEvents", () => { const roomId = "!room:example.org"; + function makeEvent(overrides: Partial): MatrixRawEvent { + return { + event_id: "$event", + sender: "@alice:example.org", + type: "m.room.message", + origin_server_ts: 0, + content: {}, + ...overrides, + }; + } + beforeEach(() => { sendReadReceiptMatrixMock.mockClear(); }); @@ -67,10 +78,10 @@ describe("registerMatrixMonitorEvents", () => { it("sends read receipt immediately for non-self messages", async () => { const { client, onRoomMessage, roomMessageHandler } = createHarness(); - const event = { + const event = makeEvent({ event_id: "$e1", sender: "@alice:example.org", - } as MatrixRawEvent; + }); roomMessageHandler("!room:example.org", event); @@ -81,22 +92,27 @@ describe("registerMatrixMonitorEvents", () => { }); it("does not send read receipts for self messages", async () => { - await expectForwardedWithoutReadReceipt({ - event_id: "$e2", - sender: "@bot:example.org", - }); + await expectForwardedWithoutReadReceipt( + makeEvent({ + event_id: "$e2", + sender: "@bot:example.org", + }), + ); }); it("skips receipt when message lacks sender or event id", async () => { - await expectForwardedWithoutReadReceipt({ - sender: "@alice:example.org", - }); + await expectForwardedWithoutReadReceipt( + makeEvent({ + sender: "@alice:example.org", + event_id: "", + }), + ); }); it("caches self user id across messages", async () => { const { getUserId, roomMessageHandler } = createHarness(); - const first = { event_id: "$e3", sender: "@alice:example.org" } as MatrixRawEvent; - const second = { event_id: "$e4", sender: "@bob:example.org" } as MatrixRawEvent; + const first = makeEvent({ event_id: "$e3", sender: "@alice:example.org" }); + const second = makeEvent({ event_id: "$e4", sender: "@bob:example.org" }); roomMessageHandler("!room:example.org", first); roomMessageHandler("!room:example.org", second); @@ -110,7 +126,7 @@ describe("registerMatrixMonitorEvents", () => { it("logs and continues when sending read receipt fails", async () => { sendReadReceiptMatrixMock.mockRejectedValueOnce(new Error("network boom")); const { roomMessageHandler, onRoomMessage, logVerboseMessage } = createHarness(); - const event = { event_id: "$e5", sender: "@alice:example.org" } as MatrixRawEvent; + const event = makeEvent({ event_id: "$e5", sender: "@alice:example.org" }); roomMessageHandler("!room:example.org", event); @@ -126,7 +142,7 @@ describe("registerMatrixMonitorEvents", () => { const { roomMessageHandler, onRoomMessage, getUserId } = createHarness({ getUserId: vi.fn().mockRejectedValue(new Error("cannot resolve self")), }); - const event = { event_id: "$e6", sender: "@alice:example.org" } as MatrixRawEvent; + const event = makeEvent({ event_id: "$e6", sender: "@alice:example.org" }); roomMessageHandler("!room:example.org", event); diff --git a/extensions/nostr/src/nostr-profile-http.test.ts b/extensions/nostr/src/nostr-profile-http.test.ts index 745ba8baed5..3caa739c6c1 100644 --- a/extensions/nostr/src/nostr-profile-http.test.ts +++ b/extensions/nostr/src/nostr-profile-http.test.ts @@ -115,6 +115,13 @@ function createMockContext(overrides?: Partial): NostrP }; } +function expectOkResponse(res: ReturnType) { + expect(res._getStatusCode()).toBe(200); + const data = JSON.parse(res._getData()); + expect(data.ok).toBe(true); + return data; +} + function mockSuccessfulProfileImport() { vi.mocked(importProfileFromRelays).mockResolvedValue({ ok: true, @@ -217,13 +224,6 @@ describe("nostr-profile-http", () => { }); } - function expectOkResponse(res: ReturnType) { - expect(res._getStatusCode()).toBe(200); - const data = JSON.parse(res._getData()); - expect(data.ok).toBe(true); - return data; - } - function expectBadRequestResponse(res: ReturnType) { expect(res._getStatusCode()).toBe(400); const data = JSON.parse(res._getData()); diff --git a/extensions/synology-chat/src/webhook-handler.test.ts b/extensions/synology-chat/src/webhook-handler.test.ts index a0b67d49aad..ae5bd061b85 100644 --- a/extensions/synology-chat/src/webhook-handler.test.ts +++ b/extensions/synology-chat/src/webhook-handler.test.ts @@ -2,6 +2,7 @@ import { EventEmitter } from "node:events"; import type { IncomingMessage, ServerResponse } from "node:http"; import { describe, it, expect, vi, beforeEach } from "vitest"; import type { ResolvedSynologyChatAccount } from "./types.js"; +import type { WebhookHandlerDeps } from "./webhook-handler.js"; import { clearSynologyWebhookRateLimiterStateForTest, createWebhookHandler, @@ -118,7 +119,7 @@ describe("createWebhookHandler", () => { async function expectForbiddenByPolicy(params: { account: Partial; bodyContains: string; - deliver?: ReturnType; + deliver?: WebhookHandlerDeps["deliver"]; }) { const deliver = params.deliver ?? vi.fn(); const handler = createWebhookHandler({ diff --git a/extensions/zalo/src/monitor.ts b/extensions/zalo/src/monitor.ts index 2c5c420ce60..d82c0d96ba4 100644 --- a/extensions/zalo/src/monitor.ts +++ b/extensions/zalo/src/monitor.ts @@ -289,7 +289,7 @@ async function handleTextMessage( } async function handleImageMessage(params: ZaloImageMessageParams): Promise { - const { message, mediaMaxMb } = params; + const { message, mediaMaxMb, account, core, runtime } = params; const { photo, caption } = message; let mediaPath: string | undefined; diff --git a/extensions/zalo/src/send.ts b/extensions/zalo/src/send.ts index c6380a3b891..4f35f242191 100644 --- a/extensions/zalo/src/send.ts +++ b/extensions/zalo/src/send.ts @@ -77,21 +77,14 @@ function resolveValidatedSendContext( return { ok: true, chatId: trimmedChatId, token, fetcher }; } -function toInvalidContextResult( - context: ReturnType, -): ZaloSendResult | null { - return context.ok ? null : { ok: false, error: context.error }; -} - export async function sendMessageZalo( chatId: string, text: string, options: ZaloSendOptions = {}, ): Promise { const context = resolveValidatedSendContext(chatId, options); - const invalidResult = toInvalidContextResult(context); - if (invalidResult) { - return invalidResult; + if (!context.ok) { + return { ok: false, error: context.error }; } if (options.mediaUrl) { @@ -120,9 +113,8 @@ export async function sendPhotoZalo( options: ZaloSendOptions = {}, ): Promise { const context = resolveValidatedSendContext(chatId, options); - const invalidResult = toInvalidContextResult(context); - if (invalidResult) { - return invalidResult; + if (!context.ok) { + return { ok: false, error: context.error }; } if (!photoUrl?.trim()) { diff --git a/src/commands/onboard-non-interactive.gateway.test.ts b/src/commands/onboard-non-interactive.gateway.test.ts index 23684eb5f5a..5396b20b9d6 100644 --- a/src/commands/onboard-non-interactive.gateway.test.ts +++ b/src/commands/onboard-non-interactive.gateway.test.ts @@ -1,6 +1,7 @@ import fs from "node:fs/promises"; import path from "node:path"; import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest"; +import type { RuntimeEnv } from "../runtime.js"; import { makeTempWorkspace } from "../test-helpers/workspace.js"; import { captureEnv } from "../test-utils/env.js"; import { createThrowingRuntime, readJsonFile } from "./onboard-non-interactive.test-helpers.js"; @@ -408,11 +409,17 @@ describe("onboard (non-interactive): gateway and remote auth", () => { })); let capturedError = ""; - const runtimeWithCapture = { + const runtimeWithCapture: RuntimeEnv = { log: () => {}, - error: (message: string) => { - capturedError = message; - throw new Error(message); + error: (...args: unknown[]) => { + const firstArg = args[0]; + capturedError = + typeof firstArg === "string" + ? firstArg + : firstArg instanceof Error + ? firstArg.message + : (JSON.stringify(firstArg) ?? ""); + throw new Error(capturedError); }, exit: (_code: number) => { throw new Error("exit should not be reached after runtime.error"); diff --git a/src/node-host/invoke-system-run.ts b/src/node-host/invoke-system-run.ts index 32bd2d6ff79..c38094dc683 100644 --- a/src/node-host/invoke-system-run.ts +++ b/src/node-host/invoke-system-run.ts @@ -34,6 +34,7 @@ import { } from "./invoke-system-run-plan.js"; import type { ExecEventPayload, + ExecFinishedResult, ExecFinishedEventParams, RunResult, SkillBinsProvider, diff --git a/src/slack/monitor/events/messages.test.ts b/src/slack/monitor/events/messages.test.ts index 25fdb77c025..f22b24a44c7 100644 --- a/src/slack/monitor/events/messages.test.ts +++ b/src/slack/monitor/events/messages.test.ts @@ -17,7 +17,6 @@ vi.mock("../../../pairing/pairing-store.js", () => ({ })); type MessageHandler = (args: { event: Record; body: unknown }) => Promise; -type AppMentionHandler = MessageHandler; type RegisteredEventName = "message" | "app_mention"; type MessageCase = {