From c82ca137da918c252104a175c2794376dfbec3c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Necati=20Y=C3=B6net?= Date: Sun, 9 Aug 2026 13:03:17 +0300 Subject: [PATCH 1/2] fix: unblock workspace build by typing bot session result as AIResult packages/bot/core and packages/bots/core both fail to compile with TS2345: the finish() callback parameter was typed with a loose { type: string; ... } shape, which is not assignable to AIResult (type must be the literal "result"). Type it as AIResult so the workspace build (tsc -p tsconfig.json) passes in both trees. Also fixes packages/bots/signal compile errors in the test file: - IncomingMessage.groupId widened to string | null | undefined (the implementation already falls back with ??, so undefined is valid) - test literal now includes isGroup and drops the unused raw field --- packages/bot/core/src/index.ts | 11 +---------- packages/bots/core/src/index.ts | 11 +---------- packages/bots/signal/src/index.test.ts | 2 +- packages/bots/signal/src/index.ts | 2 +- 4 files changed, 4 insertions(+), 22 deletions(-) diff --git a/packages/bot/core/src/index.ts b/packages/bot/core/src/index.ts index 00073aba..434f6517 100644 --- a/packages/bot/core/src/index.ts +++ b/packages/bot/core/src/index.ts @@ -111,16 +111,7 @@ export class SessionManager { proc.stderr?.on("data", (chunk) => (stderr += chunk.toString())); return new Promise((resolve) => { - const finish = (result: { - type: string; - subtype: string; - is_error: boolean; - result: string; - duration_ms: number; - num_turns: number; - session_id: string; - total_cost_usd: number; - }) => { + const finish = (result: AIResult) => { session.busy = false; session.abortController = null; resolve(result); diff --git a/packages/bots/core/src/index.ts b/packages/bots/core/src/index.ts index 9284cf07..e15d0383 100644 --- a/packages/bots/core/src/index.ts +++ b/packages/bots/core/src/index.ts @@ -111,16 +111,7 @@ export class SessionManager { proc.stderr?.on("data", (chunk) => (stderr += chunk.toString())); return new Promise((resolve) => { - const finish = (result: { - type: string; - subtype: string; - is_error: boolean; - result: string; - duration_ms: number; - num_turns: number; - session_id: string; - total_cost_usd: number; - }) => { + const finish = (result: AIResult) => { session.busy = false; session.abortController = null; resolve(result); diff --git a/packages/bots/signal/src/index.test.ts b/packages/bots/signal/src/index.test.ts index 4a479d93..c074aafb 100644 --- a/packages/bots/signal/src/index.test.ts +++ b/packages/bots/signal/src/index.test.ts @@ -59,8 +59,8 @@ describe('toBotEvent', () => { text: 'hello', timestamp: Number.POSITIVE_INFINITY, groupId: undefined, + isGroup: false, attachments: [], - raw: {}, }).timestamp).toBe('1970-01-01T00:00:00.000Z'); }); }); diff --git a/packages/bots/signal/src/index.ts b/packages/bots/signal/src/index.ts index a9bec189..8a28777f 100644 --- a/packages/bots/signal/src/index.ts +++ b/packages/bots/signal/src/index.ts @@ -24,7 +24,7 @@ export interface IncomingMessage { sourceName: string; text: string; timestamp: number; - groupId: string | null; + groupId: string | null | undefined; isGroup: boolean; attachments: Array<{ filename: string; url: string }>; } From 2c8ef71b45bc05f80d7d84f7ddc1c1f27585e61c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Necati=20Y=C3=B6net?= Date: Sun, 9 Aug 2026 13:29:18 +0300 Subject: [PATCH 2/2] fix(telegram): tolerate out-of-range message timestamps toBotEvent called new Date(msg.timestamp).toISOString() with no NaN guard. msg.date from the Telegram API can be absent/undefined (undefined * 1000 = NaN), which threw RangeError: Invalid time value and dropped the message before handlers ran. Mirrors the same fix already shipped in discord (#919), whatsapp (#920), signal (#932) and slack (#930): fall back to the epoch when the timestamp is invalid. toBotEvent is now exported so it can be tested, matching the pattern in the other bots. --- packages/bots/telegram/src/index.test.ts | 17 ++++++++++++++++- packages/bots/telegram/src/index.ts | 5 +++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/bots/telegram/src/index.test.ts b/packages/bots/telegram/src/index.test.ts index ec3b120a..a5de012c 100644 --- a/packages/bots/telegram/src/index.test.ts +++ b/packages/bots/telegram/src/index.test.ts @@ -1,9 +1,24 @@ import { describe, expect, it } from 'vitest'; import { contractTestBot } from '@profullstack/sh1pt-core/testing'; -import bot, { loadConfig, parseTelegramChatId } from './index.js'; +import bot, { loadConfig, parseTelegramChatId, toBotEvent } from './index.js'; contractTestBot(bot, { sampleConfig: {}, sampleChannel: '1234567890' }); +describe('toBotEvent', () => { + it('falls back when Telegram provides an out-of-range timestamp', () => { + expect(toBotEvent({ + source: 'user-1', + sourceName: 'User', + text: 'hello', + timestamp: Number.NaN, + chatId: 123, + isGroup: false, + attachments: [], + raw: null as never, + }).timestamp).toBe('1970-01-01T00:00:00.000Z'); + }); +}); + describe('parseTelegramChatId', () => { it('accepts positive user and negative group chat ids', () => { expect(parseTelegramChatId('1234567890')).toBe(1234567890); diff --git a/packages/bots/telegram/src/index.ts b/packages/bots/telegram/src/index.ts index c446c6a6..86f3f4f1 100644 --- a/packages/bots/telegram/src/index.ts +++ b/packages/bots/telegram/src/index.ts @@ -126,7 +126,8 @@ export function parseTelegramChatId(value: string): number { return chatId; } -function toBotEvent(msg: IncomingMessage): BotEvent { +export function toBotEvent(msg: IncomingMessage): BotEvent { + const date = new Date(msg.timestamp); return { type: "message", channel: String(msg.chatId), @@ -136,7 +137,7 @@ function toBotEvent(msg: IncomingMessage): BotEvent { }, text: msg.text, attachments: msg.attachments.map((a) => ({ url: a.url, filename: a.filename })), - timestamp: new Date(msg.timestamp).toISOString(), + timestamp: Number.isNaN(date.getTime()) ? new Date(0).toISOString() : date.toISOString(), raw: msg.raw, }; }