fix(social): friend_request_sent local broadcast must carry target profile

The local branch was reusing friendRequestPayload (built for
friend_request_received with user=sender) for the sender-side
friend_request_sent broadcast. Tab B on the sender would render
the sender's own avatar where the target's should appear.
Match the federated branch — sent broadcast carries target.
This commit is contained in:
Jannis Braun
2026-04-25 22:18:47 +02:00
parent 1ad1fd1b0c
commit d88d369a82
3 changed files with 28 additions and 11 deletions
@@ -161,14 +161,17 @@ describe('POST /api/social/requests — federated branch (happy path)', () => {
.get();
expect(mutationRow).toBeTruthy();
// WS broadcast to sender
expect(sendToUser).toHaveBeenCalledWith(
CALLER_ID,
expect.objectContaining({
type: 'friend_request_sent',
request: expect.objectContaining({ id: body.requestId }),
}),
// WS broadcast to sender — the 'user' field must carry the TARGET's profile (alice),
// not the sender. This is the federated analogue of the local-branch invariant.
const sentEvent = sendToUser.mock.calls.find(
(c: unknown[]) => (c[1] as { type?: string })?.type === 'friend_request_sent',
);
expect(sentEvent).toBeDefined();
expect(sentEvent![0]).toBe(CALLER_ID);
expect(sentEvent![1].request.id).toBe(body.requestId);
// homeUserId identifies the target; username is the canonical stub form (<homeUserId>@<host>).
expect(sentEvent![1].request.user.homeUserId).toBe('remote-alice');
expect(sentEvent![1].request.user.username).toBe('remote-alice@orbit.test');
});
});
@@ -236,5 +236,9 @@ describe('POST /api/social/requests — case-insensitive username lookup', () =>
const sent = sendToUser.mock.calls.find(c => c[1]?.type === 'friend_request_sent');
expect(sent).toBeDefined();
expect(sent![0]).toBe(CALLER_ID);
// The 'user' field on the sent payload must be the TARGET (alice),
// not the sender — symmetric with how the federated branch builds it.
expect(sent![1].request.user.id).toBe('u1');
expect(sent![1].request.user.username).toBe('alice');
});
});
+14 -4
View File
@@ -88,8 +88,8 @@ async function handleLocalFriendRequest(
createdAt: now,
}).run();
// Broadcast friend_request_received to the target user
const friendRequestPayload: FriendRequest = {
// Broadcast to the target: they need to know who sent the request (sender profile).
const receivedPayload: FriendRequest = {
id,
fromId: request.userId,
toId: targetUser.id,
@@ -98,14 +98,24 @@ async function handleLocalFriendRequest(
user: sanitizeUser(sender),
};
// Broadcast to the sender's other tabs: they need to know who they added (target profile).
const sentPayload: FriendRequest = {
id,
fromId: request.userId,
toId: targetUser.id,
status: 'pending',
createdAt: now,
user: sanitizeUser(targetUser),
};
connectionManager.sendToUser(targetUser.id, {
type: 'friend_request_received',
request: friendRequestPayload,
request: receivedPayload,
});
connectionManager.sendToUser(request.userId, {
type: 'friend_request_sent',
request: friendRequestPayload,
request: sentPayload,
});
// Federation relay: notify the target user's home instance