From 96fe85fb7799cd9e958cf93faf55df5517fb5ae8 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 7 Apr 2026 23:17:32 +0100 Subject: [PATCH] refactor: dedupe telegram trimmed readers --- extensions/telegram/src/account-inspect.ts | 14 +++++++++----- extensions/telegram/src/action-runtime.ts | 10 ++++++---- .../telegram/src/approval-handler.runtime.ts | 3 ++- extensions/telegram/src/approval-native.ts | 2 +- extensions/telegram/src/audit.test.ts | 7 +++++++ extensions/telegram/src/audit.ts | 5 +++-- extensions/telegram/src/bot-access.ts | 5 ++++- .../telegram/src/bot-native-command-menu.ts | 4 ++-- extensions/telegram/src/bot/helpers.ts | 4 +++- extensions/telegram/src/channel.ts | 19 ++++++++++--------- extensions/telegram/src/doctor.ts | 16 +++++++++------- extensions/telegram/src/exec-approvals.ts | 7 +++++-- extensions/telegram/src/secret-contract.ts | 11 +++++------ extensions/telegram/src/security-audit.ts | 12 +++++++++--- .../telegram/src/setup-surface.helpers.ts | 4 +++- extensions/telegram/src/target-writeback.ts | 7 +++++-- extensions/telegram/src/thread-bindings.ts | 7 +++---- extensions/telegram/src/webhook.ts | 4 ++-- 18 files changed, 88 insertions(+), 53 deletions(-) diff --git a/extensions/telegram/src/account-inspect.ts b/extensions/telegram/src/account-inspect.ts index f60a6340e91..ccaf2a6ec74 100644 --- a/extensions/telegram/src/account-inspect.ts +++ b/extensions/telegram/src/account-inspect.ts @@ -34,7 +34,7 @@ function inspectTokenFile(pathValue: unknown): { tokenSource: "tokenFile" | "none"; tokenStatus: TelegramCredentialStatus; } | null { - const tokenFile = typeof pathValue === "string" ? pathValue.trim() : ""; + const tokenFile = normalizeOptionalString(pathValue) ?? ""; if (!tokenFile) { return null; } @@ -85,10 +85,10 @@ function inspectTokenValue(params: { cfg: OpenClawConfig; value: unknown }): { tokenStatus: "configured_unavailable", }; } - const envValue = process.env[ref.id]; - if (envValue && envValue.trim()) { + const envValue = normalizeOptionalString(process.env[ref.id]); + if (envValue) { return { - token: envValue.trim(), + token: envValue, tokenSource: "env", tokenStatus: "available", }; @@ -187,7 +187,11 @@ function inspectTelegramAccountPrimary(params: { } const allowEnv = accountId === DEFAULT_ACCOUNT_ID; - const envToken = allowEnv ? (params.envToken ?? process.env.TELEGRAM_BOT_TOKEN)?.trim() : ""; + const envToken = allowEnv + ? (normalizeOptionalString(params.envToken) ?? + normalizeOptionalString(process.env.TELEGRAM_BOT_TOKEN) ?? + "") + : ""; if (envToken) { return { accountId, diff --git a/extensions/telegram/src/action-runtime.ts b/extensions/telegram/src/action-runtime.ts index f4b2f1ebd03..f9791729bf2 100644 --- a/extensions/telegram/src/action-runtime.ts +++ b/extensions/telegram/src/action-runtime.ts @@ -11,7 +11,10 @@ import { resolveReactionMessageId, } from "openclaw/plugin-sdk/channel-actions"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; -import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime"; +import { + normalizeOptionalLowercaseString, + normalizeOptionalString, +} from "openclaw/plugin-sdk/text-runtime"; import { createTelegramActionGate, resolveTelegramPollActionGateState } from "./accounts.js"; import { fitsTelegramCallbackData, @@ -114,9 +117,8 @@ export function readTelegramButtons( throw new Error(`buttons[${rowIndex}][${buttonIndex}] must be an object`); } const rawButton = button as RawTelegramButton; - const text = typeof rawButton.text === "string" ? rawButton.text.trim() : ""; - const callbackData = - typeof rawButton.callback_data === "string" ? rawButton.callback_data.trim() : ""; + const text = normalizeOptionalString(rawButton.text) ?? ""; + const callbackData = normalizeOptionalString(rawButton.callback_data) ?? ""; if (!text || !callbackData) { throw new Error(`buttons[${rowIndex}][${buttonIndex}] requires text and callback_data`); } diff --git a/extensions/telegram/src/approval-handler.runtime.ts b/extensions/telegram/src/approval-handler.runtime.ts index 7fc7d98da45..2ef9fef9e1b 100644 --- a/extensions/telegram/src/approval-handler.runtime.ts +++ b/extensions/telegram/src/approval-handler.runtime.ts @@ -13,6 +13,7 @@ import { type PluginApprovalRequest, } from "openclaw/plugin-sdk/infra-runtime"; import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; import { resolveTelegramInlineButtons } from "./button-types.js"; import { isTelegramExecApprovalHandlerConfigured, @@ -49,7 +50,7 @@ function resolveHandlerContext(params: ChannelApprovalCapabilityHandlerContext): context: TelegramApprovalHandlerContext; } | null { const context = params.context as TelegramApprovalHandlerContext | undefined; - const accountId = params.accountId?.trim() || ""; + const accountId = normalizeOptionalString(params.accountId) ?? ""; if (!context?.token || !accountId) { return null; } diff --git a/extensions/telegram/src/approval-native.ts b/extensions/telegram/src/approval-native.ts index 454590dd1b6..81de92516da 100644 --- a/extensions/telegram/src/approval-native.ts +++ b/extensions/telegram/src/approval-native.ts @@ -34,7 +34,7 @@ function resolveTurnSourceTelegramOriginTarget( request: ApprovalRequest, ): TelegramOriginTarget | null { const turnSourceChannel = normalizeLowercaseStringOrEmpty(request.request.turnSourceChannel); - const rawTurnSourceTo = request.request.turnSourceTo?.trim() || ""; + const rawTurnSourceTo = normalizeOptionalString(request.request.turnSourceTo) ?? ""; const parsedTurnSourceTarget = rawTurnSourceTo ? parseTelegramTarget(rawTurnSourceTo) : null; const turnSourceTo = normalizeTelegramChatId(parsedTurnSourceTarget?.chatId ?? rawTurnSourceTo); if (turnSourceChannel !== "telegram" || !turnSourceTo) { diff --git a/extensions/telegram/src/audit.test.ts b/extensions/telegram/src/audit.test.ts index fc4ce4a069c..1f8684adc60 100644 --- a/extensions/telegram/src/audit.test.ts +++ b/extensions/telegram/src/audit.test.ts @@ -10,6 +10,13 @@ vi.mock("openclaw/plugin-sdk/text-runtime", () => ({ fetchWithTimeout: fetchWithTimeoutMock, isRecord: (value: unknown): value is Record => typeof value === "object" && value !== null, + normalizeOptionalString: (value: unknown) => { + if (typeof value !== "string") { + return undefined; + } + const trimmed = value.trim(); + return trimmed ? trimmed : undefined; + }, })); function mockGetChatMemberStatus(status: string) { diff --git a/extensions/telegram/src/audit.ts b/extensions/telegram/src/audit.ts index f205dc49127..03ff16071e3 100644 --- a/extensions/telegram/src/audit.ts +++ b/extensions/telegram/src/audit.ts @@ -1,5 +1,6 @@ import type { TelegramGroupConfig } from "openclaw/plugin-sdk/config-runtime"; import type { TelegramNetworkConfig } from "openclaw/plugin-sdk/config-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; export type TelegramGroupMembershipAuditEntry = { chatId: string; @@ -46,7 +47,7 @@ export function collectTelegramUnmentionedGroupIds( if (value.requireMention !== false) { continue; } - const id = String(key).trim(); + const id = normalizeOptionalString(String(key)) ?? ""; if (!id) { continue; } @@ -82,7 +83,7 @@ export async function auditTelegramGroupMembership( params: AuditTelegramGroupMembershipParams, ): Promise { const started = Date.now(); - const token = params.token?.trim() ?? ""; + const token = normalizeOptionalString(params.token) ?? ""; if (!token || params.groupIds.length === 0) { return { ok: true, diff --git a/extensions/telegram/src/bot-access.ts b/extensions/telegram/src/bot-access.ts index 82034aeadb2..b0f804e8610 100644 --- a/extensions/telegram/src/bot-access.ts +++ b/extensions/telegram/src/bot-access.ts @@ -5,6 +5,7 @@ import { type AllowlistMatch, } from "openclaw/plugin-sdk/allow-from"; import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; export type NormalizedAllowFrom = { entries: string[]; @@ -40,7 +41,9 @@ function warnInvalidAllowFromEntries(entries: string[]) { } export const normalizeAllowFrom = (list?: Array): NormalizedAllowFrom => { - const entries = (list ?? []).map((value) => String(value).trim()).filter(Boolean); + const entries = (list ?? []) + .map((value) => normalizeOptionalString(String(value)) ?? "") + .filter(Boolean); const hasWildcard = entries.includes("*"); const normalized = entries .filter((value) => value !== "*") diff --git a/extensions/telegram/src/bot-native-command-menu.ts b/extensions/telegram/src/bot-native-command-menu.ts index 0605302531b..82f1fe4fab1 100644 --- a/extensions/telegram/src/bot-native-command-menu.ts +++ b/extensions/telegram/src/bot-native-command-menu.ts @@ -6,7 +6,7 @@ import type { Bot } from "grammy"; import { logVerbose } from "openclaw/plugin-sdk/runtime-env"; import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { resolveStateDir } from "openclaw/plugin-sdk/state-paths"; -import { readStringValue } from "openclaw/plugin-sdk/text-runtime"; +import { normalizeOptionalString, readStringValue } from "openclaw/plugin-sdk/text-runtime"; import { withTelegramApiErrorLogging } from "./api-logging.js"; import { normalizeTelegramCommandName, TELEGRAM_COMMAND_NAME_PATTERN } from "./command-config.js"; @@ -154,7 +154,7 @@ export function buildPluginTelegramMenuCommands(params: { ); continue; } - const description = typeof spec.description === "string" ? spec.description.trim() : ""; + const description = normalizeOptionalString(spec.description) ?? ""; if (!description) { issues.push(`Plugin command "/${normalized}" is missing a description.`); continue; diff --git a/extensions/telegram/src/bot/helpers.ts b/extensions/telegram/src/bot/helpers.ts index 7066afb7b48..4d176f30a28 100644 --- a/extensions/telegram/src/bot/helpers.ts +++ b/extensions/telegram/src/bot/helpers.ts @@ -7,6 +7,7 @@ import type { } from "openclaw/plugin-sdk/config-runtime"; import { readChannelAllowFromStore } from "openclaw/plugin-sdk/conversation-runtime"; import { normalizeAccountId } from "openclaw/plugin-sdk/routing"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; import { firstDefined, normalizeAllowFrom, type NormalizedAllowFrom } from "../bot-access.js"; import { normalizeTelegramReplyToMessageId } from "../outbound-params.js"; import { resolveTelegramPreviewStreamMode } from "../preview-streaming.js"; @@ -279,7 +280,8 @@ export function resolveTelegramDirectPeerId(params: { chatId: number | string; senderId?: number | string | null; }) { - const senderId = params.senderId != null ? String(params.senderId).trim() : ""; + const senderId = + params.senderId != null ? (normalizeOptionalString(String(params.senderId)) ?? "") : ""; if (senderId) { return senderId; } diff --git a/extensions/telegram/src/channel.ts b/extensions/telegram/src/channel.ts index 0e9f67e0158..be2930fa97a 100644 --- a/extensions/telegram/src/channel.ts +++ b/extensions/telegram/src/channel.ts @@ -276,13 +276,13 @@ function targetsMatchTelegramReplySuppression(params: { const origin = parseTelegramTarget(params.originTarget); const target = parseTelegramTarget(params.targetKey); const originThreadId = - origin.messageThreadId != null && String(origin.messageThreadId).trim() - ? String(origin.messageThreadId).trim() + origin.messageThreadId != null && normalizeOptionalString(String(origin.messageThreadId)) + ? normalizeOptionalString(String(origin.messageThreadId)) : undefined; const targetThreadId = - params.targetThreadId?.trim() || - (target.messageThreadId != null && String(target.messageThreadId).trim() - ? String(target.messageThreadId).trim() + normalizeOptionalString(params.targetThreadId) || + (target.messageThreadId != null && normalizeOptionalString(String(target.messageThreadId)) + ? normalizeOptionalString(String(target.messageThreadId)) : undefined); if ( normalizeOptionalLowercaseString(origin.chatId) !== @@ -304,8 +304,8 @@ function resolveTelegramCommandConversation(params: { }) { const chatId = [params.originatingTo, params.commandTo, params.fallbackTo] .map((candidate) => { - const trimmed = candidate?.trim(); - return trimmed ? parseTelegramTarget(trimmed).chatId.trim() : ""; + const trimmed = normalizeOptionalString(candidate) ?? ""; + return trimmed ? (normalizeOptionalString(parseTelegramTarget(trimmed).chatId) ?? "") : ""; }) .find((candidate) => candidate.length > 0); if (!chatId) { @@ -331,12 +331,13 @@ function resolveTelegramInboundConversation(params: { conversationId?: string; threadId?: string | number; }) { - const rawTarget = params.to?.trim() || params.conversationId?.trim() || ""; + const rawTarget = + normalizeOptionalString(params.to) ?? normalizeOptionalString(params.conversationId) ?? ""; if (!rawTarget) { return null; } const parsedTarget = parseTelegramTarget(rawTarget); - const chatId = parsedTarget.chatId.trim(); + const chatId = normalizeOptionalString(parsedTarget.chatId) ?? ""; if (!chatId) { return null; } diff --git a/extensions/telegram/src/doctor.ts b/extensions/telegram/src/doctor.ts index e61b6ecdcba..662f35826d1 100644 --- a/extensions/telegram/src/doctor.ts +++ b/extensions/telegram/src/doctor.ts @@ -4,6 +4,7 @@ import { } from "openclaw/plugin-sdk/channel-contract"; import { type OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; import { inspectTelegramAccount } from "./account-inspect.js"; import { listTelegramAccountIds, resolveTelegramAccount } from "./accounts.js"; import { isNumericTelegramUserId, normalizeTelegramAllowFromEntry } from "./allow-from.js"; @@ -34,7 +35,7 @@ function sanitizeForLog(value: string): string { } function hasAllowFromEntries(values?: DoctorAllowFromList): boolean { - return Array.isArray(values) && values.some((entry) => String(entry).trim()); + return Array.isArray(values) && values.some((entry) => normalizeOptionalString(String(entry))); } function collectTelegramAccountScopes( @@ -113,7 +114,7 @@ export function scanTelegramAllowFromUsernameEntries( if (!normalized || normalized === "*" || isNumericTelegramUserId(normalized)) { continue; } - hits.push({ path: pathLabel, entry: String(entry).trim() }); + hits.push({ path: pathLabel, entry: normalizeOptionalString(String(entry)) ?? "" }); } }; @@ -177,7 +178,8 @@ export async function maybeRepairTelegramAllowFromUsernames(cfg: OpenClawConfig) `- Telegram account ${accountId}: failed to inspect bot token (configured but unavailable in this command path).`, ); } - const token = inspected.tokenSource === "none" ? "" : inspected.token.trim(); + const token = + inspected.tokenSource === "none" ? "" : (normalizeOptionalString(inspected.token) ?? ""); if (token) { resolverAccountIds.push(accountId); } @@ -195,7 +197,7 @@ export async function maybeRepairTelegramAllowFromUsernames(cfg: OpenClawConfig) }; } const resolveUserId = async (raw: string): Promise => { - const trimmed = raw.trim(); + const trimmed = normalizeOptionalString(raw) ?? ""; if (!trimmed) { return null; } @@ -252,15 +254,15 @@ export async function maybeRepairTelegramAllowFromUsernames(cfg: OpenClawConfig) const resolved = await resolveUserId(String(entry)); if (resolved) { out.push(resolved); - replaced.push({ from: String(entry).trim(), to: resolved }); + replaced.push({ from: normalizeOptionalString(String(entry)) ?? "", to: resolved }); } else { - out.push(String(entry).trim()); + out.push(normalizeOptionalString(String(entry)) ?? ""); } } const deduped: DoctorAllowFromList = []; const seen = new Set(); for (const entry of out) { - const keyValue = String(entry).trim(); + const keyValue = normalizeOptionalString(String(entry)) ?? ""; if (!keyValue || seen.has(keyValue)) { continue; } diff --git a/extensions/telegram/src/exec-approvals.ts b/extensions/telegram/src/exec-approvals.ts index 238c6b5832b..719a581118f 100644 --- a/extensions/telegram/src/exec-approvals.ts +++ b/extensions/telegram/src/exec-approvals.ts @@ -11,13 +11,16 @@ import type { TelegramExecApprovalConfig } from "openclaw/plugin-sdk/config-runt import type { ExecApprovalRequest, PluginApprovalRequest } from "openclaw/plugin-sdk/infra-runtime"; import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime"; import { normalizeAccountId } from "openclaw/plugin-sdk/routing"; -import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime"; +import { + normalizeLowercaseStringOrEmpty, + normalizeOptionalString, +} from "openclaw/plugin-sdk/text-runtime"; import { listTelegramAccountIds, resolveTelegramAccount } from "./accounts.js"; import { resolveTelegramInlineButtonsConfigScope } from "./inline-buttons.js"; import { normalizeTelegramChatId, resolveTelegramTargetChatType } from "./targets.js"; function normalizeApproverId(value: string | number): string { - return String(value).trim(); + return normalizeOptionalString(String(value)) ?? ""; } function normalizeTelegramDirectApproverId(value: string | number): string | undefined { diff --git a/extensions/telegram/src/secret-contract.ts b/extensions/telegram/src/secret-contract.ts index 344d3b86ec6..6f9e758f3ab 100644 --- a/extensions/telegram/src/secret-contract.ts +++ b/extensions/telegram/src/secret-contract.ts @@ -7,6 +7,7 @@ import { type SecretDefaults, type SecretTargetRegistryEntry, } from "openclaw/plugin-sdk/channel-secret-basic-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; export const secretTargetRegistryEntries = [ { @@ -65,9 +66,9 @@ export function collectRuntimeConfigAssignments(params: { return; } const { channel: telegram, surface } = resolved; - const baseTokenFile = typeof telegram.tokenFile === "string" ? telegram.tokenFile.trim() : ""; + const baseTokenFile = normalizeOptionalString(telegram.tokenFile) ?? ""; const accountTokenFile = (account: Record) => - typeof account.tokenFile === "string" ? account.tokenFile.trim() : ""; + normalizeOptionalString(account.tokenFile) ?? ""; collectConditionalChannelFieldAssignments({ channelKey: "telegram", field: "botToken", @@ -91,12 +92,10 @@ export function collectRuntimeConfigAssignments(params: { "no enabled Telegram surface inherits this top-level botToken (tokenFile is configured).", accountInactiveReason: "Telegram account is disabled or tokenFile is configured.", }); - const baseWebhookUrl = typeof telegram.webhookUrl === "string" ? telegram.webhookUrl.trim() : ""; + const baseWebhookUrl = normalizeOptionalString(telegram.webhookUrl) ?? ""; const accountWebhookUrl = (account: Record) => hasOwnProperty(account, "webhookUrl") - ? typeof account.webhookUrl === "string" - ? account.webhookUrl.trim() - : "" + ? (normalizeOptionalString(account.webhookUrl) ?? "") : baseWebhookUrl; collectConditionalChannelFieldAssignments({ channelKey: "telegram", diff --git a/extensions/telegram/src/security-audit.ts b/extensions/telegram/src/security-audit.ts index be87bcc6774..bdb68ae81d9 100644 --- a/extensions/telegram/src/security-audit.ts +++ b/extensions/telegram/src/security-audit.ts @@ -1,6 +1,7 @@ import { resolveNativeSkillsEnabled } from "openclaw/plugin-sdk/config-runtime"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { readChannelAllowFromStore } from "openclaw/plugin-sdk/conversation-runtime"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; import type { ResolvedTelegramAccount } from "./accounts.js"; import { isNumericTelegramUserId, normalizeTelegramAllowFromEntry } from "./allow-from.js"; @@ -36,7 +37,8 @@ export async function collectTelegramSecurityAuditFindings(params: { } const telegramCfg = params.account.config ?? {}; - const accountId = params.accountId?.trim() || params.account.accountId || "default"; + const accountId = + normalizeOptionalString(params.accountId) ?? params.account.accountId ?? "default"; const defaultGroupPolicy = params.cfg.channels?.defaults?.groupPolicy; const groupPolicy = (telegramCfg.groupPolicy as string | undefined) ?? defaultGroupPolicy ?? "allowlist"; @@ -51,7 +53,9 @@ export async function collectTelegramSecurityAuditFindings(params: { const storeAllowFrom = await readChannelAllowFromStore("telegram", process.env, accountId).catch( () => [], ); - const storeHasWildcard = storeAllowFrom.some((value) => String(value).trim() === "*"); + const storeHasWildcard = storeAllowFrom.some( + (value) => (normalizeOptionalString(String(value)) ?? "") === "*", + ); const invalidTelegramAllowFromEntries = new Set(); collectInvalidTelegramAllowFromEntries({ entries: storeAllowFrom, @@ -60,7 +64,9 @@ export async function collectTelegramSecurityAuditFindings(params: { const groupAllowFrom = Array.isArray(telegramCfg.groupAllowFrom) ? telegramCfg.groupAllowFrom : []; - const groupAllowFromHasWildcard = groupAllowFrom.some((value) => String(value).trim() === "*"); + const groupAllowFromHasWildcard = groupAllowFrom.some( + (value) => (normalizeOptionalString(String(value)) ?? "") === "*", + ); collectInvalidTelegramAllowFromEntries({ entries: groupAllowFrom, target: invalidTelegramAllowFromEntries, diff --git a/extensions/telegram/src/setup-surface.helpers.ts b/extensions/telegram/src/setup-surface.helpers.ts index 7ef11e961f3..b0b0a50123d 100644 --- a/extensions/telegram/src/setup-surface.helpers.ts +++ b/extensions/telegram/src/setup-surface.helpers.ts @@ -7,6 +7,7 @@ import { patchChannelConfigForAccount, } from "openclaw/plugin-sdk/setup"; import { formatCliCommand, formatDocsLink } from "openclaw/plugin-sdk/setup-tools"; +import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; import { mergeTelegramAccountConfig, resolveDefaultTelegramAccountId, @@ -45,7 +46,8 @@ export function shouldShowTelegramDmAccessWarning(cfg: OpenClawConfig, accountId const merged = mergeTelegramAccountConfig(cfg, accountId); const policy = merged.dmPolicy ?? "pairing"; const hasAllowFrom = - Array.isArray(merged.allowFrom) && merged.allowFrom.some((entry) => String(entry).trim()); + Array.isArray(merged.allowFrom) && + merged.allowFrom.some((entry) => normalizeOptionalString(String(entry))); return policy === "pairing" && !hasAllowFrom; } diff --git a/extensions/telegram/src/target-writeback.ts b/extensions/telegram/src/target-writeback.ts index c7f59f55a1e..521297b3533 100644 --- a/extensions/telegram/src/target-writeback.ts +++ b/extensions/telegram/src/target-writeback.ts @@ -9,7 +9,10 @@ import { saveCronStore, } from "openclaw/plugin-sdk/config-runtime"; import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env"; -import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime"; +import { + normalizeLowercaseStringOrEmpty, + normalizeOptionalString, +} from "openclaw/plugin-sdk/text-runtime"; import { normalizeTelegramChatId, normalizeTelegramLookupTarget, @@ -89,7 +92,7 @@ function rewriteTargetIfMatch(params: { if (typeof params.rawValue !== "string" && typeof params.rawValue !== "number") { return null; } - const value = String(params.rawValue).trim(); + const value = normalizeOptionalString(String(params.rawValue)) ?? ""; if (!value) { return null; } diff --git a/extensions/telegram/src/thread-bindings.ts b/extensions/telegram/src/thread-bindings.ts index 71d96cc6fa1..e2b338f44c6 100644 --- a/extensions/telegram/src/thread-bindings.ts +++ b/extensions/telegram/src/thread-bindings.ts @@ -253,8 +253,7 @@ function loadBindingsFromDisk(accountId: string): TelegramThreadBindingRecord[] const bindings: TelegramThreadBindingRecord[] = []; for (const entry of parsed.bindings) { const conversationId = normalizeOptionalString(entry?.conversationId); - const targetSessionKey = - typeof entry?.targetSessionKey === "string" ? entry.targetSessionKey.trim() : ""; + const targetSessionKey = normalizeOptionalString(entry?.targetSessionKey) ?? ""; const targetKind = entry?.targetKind === "subagent" ? "subagent" : "acp"; if (!conversationId || !targetSessionKey) { continue; @@ -591,8 +590,8 @@ export function createTelegramThreadBindingManager( return null; } const threadName = - (typeof metadata.threadName === "string" ? metadata.threadName.trim() : "") || - (typeof metadata.label === "string" ? metadata.label.trim() : "") || + (normalizeOptionalString(metadata.threadName) ?? "") || + (normalizeOptionalString(metadata.label) ?? "") || `Agent: ${targetSessionKey.split(":").pop()}`; try { const tokenResolution = resolveTelegramToken(cfg, { accountId }); diff --git a/extensions/telegram/src/webhook.ts b/extensions/telegram/src/webhook.ts index 9a52f26da23..eec8b7e0428 100644 --- a/extensions/telegram/src/webhook.ts +++ b/extensions/telegram/src/webhook.ts @@ -139,7 +139,7 @@ function isTrustedProxyAddress( } const blockList = new net.BlockList(); for (const proxy of trustedProxies) { - const trimmed = proxy.trim(); + const trimmed = normalizeOptionalString(proxy) ?? ""; if (!trimmed) { continue; } @@ -251,7 +251,7 @@ export async function startTelegramWebhook(opts: { const healthPath = opts.healthPath ?? "/healthz"; const port = opts.port ?? 8787; const host = opts.host ?? "127.0.0.1"; - const secret = typeof opts.secret === "string" ? opts.secret.trim() : ""; + const secret = normalizeOptionalString(opts.secret) ?? ""; if (!secret) { throw new Error( "Telegram webhook mode requires a non-empty secret token. " +