fix(presence): broadcast presence_update to friends + DM members + space members

Six WS sites that previously broadcast presence_update to spaces only now use
collectProfileBroadcastTargetIds (the same recipient set as user_updated):
  - ws/handler.ts finalizeDisconnect (offline)
  - ws/handler.ts auth path (online)
  - ws/events.ts handlePresenceUpdate (manual idle/dnd/online)
  - ws/events.ts handleActivityUpdate (rich activity changes)
  - routes/users.ts showActivity-toggle clear
  - routes/users.ts status PATCH

Friends with no shared space + DM-only co-members now see each other's
online/offline transitions live, matching user_updated semantics. Federated
stub presence broadcasts (Task B3) use the same helper, so cross-instance
recipients are uniform.

Updates one assertion in social.federated.test.ts that asserted the old
snowflake-style stub username (now realname-based per A1).
This commit is contained in:
Jannis Braun
2026-05-05 16:06:45 +02:00
parent 53fe7d2b53
commit ad1a0f7164
4 changed files with 36 additions and 45 deletions
+8 -15
View File
@@ -436,16 +436,14 @@ export async function userRoutes(app: FastifyInstance): Promise<void> {
connectionManager.setUserShowActivity(request.userId, showActivity);
if (!showActivity) {
connectionManager.clearUserActivities(request.userId);
const userSpaces = connectionManager.getUserSpaces(request.userId);
const clearPayload = {
type: 'presence_update' as const,
userId: request.userId,
status: connectionManager.getUserStatus(request.userId),
activities: [] as Activity[],
};
for (const spaceId of userSpaces) {
connectionManager.sendToSpace(spaceId, clearPayload, request.userId);
}
const clearTargets = collectProfileBroadcastTargetIds(request.userId);
for (const uid of clearTargets) connectionManager.sendToUser(uid, clearPayload);
connectionManager.sendToUser(request.userId, clearPayload);
// S2S: project the cleared-activities snapshot to all active peers.
@@ -498,19 +496,14 @@ export async function userRoutes(app: FastifyInstance): Promise<void> {
// Broadcast presence update if status changed
if (status !== undefined) {
const userSpaces = connectionManager.getUserSpaces(sanitized.id);
for (const spaceId of userSpaces) {
connectionManager.sendToSpace(spaceId, {
type: 'presence_update',
userId: sanitized.id,
status: status,
}, sanitized.id);
}
connectionManager.sendToUser(sanitized.id, {
type: 'presence_update',
const statusPayload = {
type: 'presence_update' as const,
userId: sanitized.id,
status: status,
});
};
const statusTargets = collectProfileBroadcastTargetIds(sanitized.id);
for (const uid of statusTargets) connectionManager.sendToUser(uid, statusPayload);
connectionManager.sendToUser(sanitized.id, statusPayload);
}
// Broadcast user_updated for profile field changes