fix: presence MaxListeners leak + self-host fonts to fix tracking prevention
CI / Build & Quality Checks (push) Successful in 10m29s
Trigger Desktop Build / trigger (push) Successful in 5s

Presence: subscribe on MatrixClient (mx) instead of individual User objects.
User EventEmitters have a 10-listener default; the same user appears in many
mounted components simultaneously (member list, avatars, presence rings) and
was accumulating 11+ listeners per event, causing MaxListenersExceededWarning
on User.presence, User.currentlyActive, and User.lastPresenceTs.

Fonts: download JetBrains Mono and Fira Code latin subsets to public/fonts/
and replace Google Fonts CDN links (two external origins) with a local CSS
file. Windows WebView2 tracking prevention was blocking googleapis.com and
gstatic.com, logging 18+ "blocked" warnings per session. VT323 remains on
Google Fonts as it's decorative and not a default option.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 18:39:03 -04:00
parent a30a3d3a47
commit 77a29ed3c6
11 changed files with 88 additions and 9 deletions
+12 -8
View File
@@ -29,20 +29,24 @@ export const useUserPresence = (userId: string): UserPresence | undefined => {
const [presence, setPresence] = useState(() => (user ? getUserPresence(user) : undefined));
useEffect(() => {
// Subscribe on mx (MatrixClient) rather than on individual User objects.
// User objects have a default 10-listener limit; the same user can appear
// in many components simultaneously (avatars, member list, etc.) and
// per-user subscription causes MaxListenersExceededWarning at 11+.
const updatePresence: UserEventHandlerMap[UserEvent.Presence] = (event, u) => {
if (u.userId === user?.userId) {
setPresence(getUserPresence(user));
setPresence(getUserPresence(u));
}
};
user?.on(UserEvent.Presence, updatePresence);
user?.on(UserEvent.CurrentlyActive, updatePresence);
user?.on(UserEvent.LastPresenceTs, updatePresence);
mx.on(UserEvent.Presence, updatePresence);
mx.on(UserEvent.CurrentlyActive, updatePresence);
mx.on(UserEvent.LastPresenceTs, updatePresence);
return () => {
user?.removeListener(UserEvent.Presence, updatePresence);
user?.removeListener(UserEvent.CurrentlyActive, updatePresence);
user?.removeListener(UserEvent.LastPresenceTs, updatePresence);
mx.removeListener(UserEvent.Presence, updatePresence);
mx.removeListener(UserEvent.CurrentlyActive, updatePresence);
mx.removeListener(UserEvent.LastPresenceTs, updatePresence);
};
}, [user]);
}, [mx, user]);
return presence;
};