feat: stateless federated identity resolver + federation UX improvements

Add identity.ts with isSelf() and resolveDisplayIdentity() — pure
stateless functions that detect replicated-self using the immutable
(username, homeInstance) composite key. No store lookups, no data
mutation. Fixes wrong avatar gradient and missing edit/delete on
own messages in remote channels.

Also includes: optimistic message dedup fix for cross-instance
messages (content-only matching), federation toast notifications,
Username component with @domain display, invite parser, and
deploy script simplification.
This commit is contained in:
Jannis Braun
2026-03-04 03:37:49 +01:00
parent 64fd8edfc9
commit dca9c4dc83
19 changed files with 713 additions and 110 deletions
+36
View File
@@ -379,6 +379,24 @@ export async function serverRoutes(app: FastifyInstance): Promise<void> {
// Register the user in connectionManager so they receive WS broadcasts for this server
connectionManager.addUserServer(request.userId, id);
// Broadcast member_joined to existing server members
const joiningUser = db.select().from(schema.users).where(eq(schema.users.id, request.userId)).get();
if (joiningUser) {
const memberPayload: MemberWithUser = {
serverId: id,
userId: request.userId,
nickname: null,
joinedAt: now,
user: sanitizeUser(joiningUser),
roles: [],
};
connectionManager.sendToServer(id, {
type: 'member_joined',
serverId: id,
member: memberPayload,
});
}
return reply.code(200).send(rowToServer(server));
});
@@ -413,6 +431,24 @@ export async function serverRoutes(app: FastifyInstance): Promise<void> {
// Register the user in connectionManager so they receive WS broadcasts for this server
connectionManager.addUserServer(request.userId, server.id);
// Broadcast member_joined to existing server members
const joiningUser = db.select().from(schema.users).where(eq(schema.users.id, request.userId)).get();
if (joiningUser) {
const memberPayload: MemberWithUser = {
serverId: server.id,
userId: request.userId,
nickname: null,
joinedAt: now,
user: sanitizeUser(joiningUser),
roles: [],
};
connectionManager.sendToServer(server.id, {
type: 'member_joined',
serverId: server.id,
member: memberPayload,
});
}
return reply.code(200).send(rowToServer(server));
});