fix telegram contact identity context for in/out messages

This commit is contained in:
Ruslan Bakiev
2026-02-23 19:28:03 +07:00
parent 79f1012f41
commit 94d8d46693
2 changed files with 35 additions and 20 deletions

View File

@@ -212,19 +212,12 @@ function buildContactProfile(
normalized: OmniInboundEnvelopeV1["payloadNormalized"], normalized: OmniInboundEnvelopeV1["payloadNormalized"],
externalContactId: string, externalContactId: string,
): ContactProfile { ): ContactProfile {
const firstName = // Use only normalized contact-* fields (counterparty), avoid sender/chat fallbacks
asString(normalized.contactFirstName) ?? // to prevent accidental renames to the business owner name on OUT events.
asString(normalized.fromFirstName) ?? const firstName = asString(normalized.contactFirstName);
asString(normalized.chatFirstName); const lastName = asString(normalized.contactLastName);
const lastName = const username = asString(normalized.contactUsername);
asString(normalized.contactLastName) ?? const title = asString(normalized.contactTitle);
asString(normalized.fromLastName) ??
asString(normalized.chatLastName);
const username =
asString(normalized.contactUsername) ??
asString(normalized.fromUsername) ??
asString(normalized.chatUsername);
const title = asString(normalized.contactTitle) ?? asString(normalized.chatTitle);
const fullName = [firstName, lastName].filter(Boolean).join(" "); const fullName = [firstName, lastName].filter(Boolean).join(" ");
const displayName = const displayName =

View File

@@ -60,6 +60,12 @@ function normalizeNumber(value: unknown) {
return null; return null;
} }
function normalizeId(value: unknown) {
if (value == null) return null;
const text = String(value).trim();
return text || null;
}
type TelegramMediaInfo = { type TelegramMediaInfo = {
kind: "voice" | "audio" | "video_note" | null; kind: "voice" | "audio" | "video_note" | null;
fileId: string | null; fileId: string | null;
@@ -159,8 +165,26 @@ export function parseTelegramBusinessUpdate(raw: unknown): OmniInboundEnvelopeV1
const chat = asObject(message.chat); const chat = asObject(message.chat);
const from = asObject(message.from); const from = asObject(message.from);
const direction = detectDirection(message, chat, from); const direction = detectDirection(message, chat, from);
const contactSource = direction === "OUT" && Object.keys(chat).length > 0 ? chat : from; const ownerChatId = normalizeId(businessConnection.user_chat_id);
const fallbackContactSource = direction === "OUT" ? from : chat; const chatId = normalizeId(chat.id);
const fromId = normalizeId(from.id);
let contactSource: JsonObject | null = null;
if (ownerChatId) {
// Prefer the counterparty id/source (different from connected owner chat id).
if (chatId && chatId !== ownerChatId) contactSource = chat;
if (fromId && fromId !== ownerChatId) {
if (!contactSource || direction === "IN") {
contactSource = from;
}
}
}
if (!contactSource) {
contactSource = direction === "OUT" && Object.keys(chat).length > 0 ? chat : from;
}
const fallbackContactSource = contactSource === chat ? from : chat;
const threadExternalId = const threadExternalId =
chat.id != null chat.id != null
@@ -170,11 +194,9 @@ export function parseTelegramBusinessUpdate(raw: unknown): OmniInboundEnvelopeV1
: null; : null;
const contactExternalId = const contactExternalId =
contactSource.id != null normalizeId(contactSource?.id) ??
? String(contactSource.id) normalizeId(fallbackContactSource?.id) ??
: fallbackContactSource.id != null null;
? String(fallbackContactSource.id)
: null;
const media = pickTelegramMedia(message); const media = pickTelegramMedia(message);
const text = const text =