const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i export type ParticipantDisplayUser = { id?: string name?: string | null username?: string | null } export function isUuidLike(value: string): boolean { return UUID_REGEX.test(value.trim()) } function isUsableDisplayValue( value: string | null | undefined, userId?: string ): value is string { const trimmed = value?.trim() if (!trimmed) return false if (userId && trimmed === userId) return false // Followers with no real name were historically provisioned in Stream Chat with a // placeholder name of the form `Follower ` (the string "Follower " + the user id). // Treat it as missing so surfaces fall back to their own label instead of leaking the // internal placeholder as a display name (MES-1077). if (userId && trimmed === `Follower ${userId}`) return false return !isUuidLike(trimmed) } /** * Resolves a human-readable participant label from Stream user fields. * Never falls back to user.id. UUID-like names are treated as missing. */ export function resolveParticipantDisplayName( user?: ParticipantDisplayUser | null ): string { if (isUsableDisplayValue(user?.name, user?.id)) { return user.name.trim() } if (isUsableDisplayValue(user?.username, user?.id)) { return user.username.trim() } return 'Unknown member' }