feat(chat): rekeyChannelState moves channel state from oldId to newId

Deletes every channel-keyed entry under oldId (messages, hasMore,
typingUsers, readStates, channelAccessTimes, scrollPositions) without
seeding newId — subscribers refetch naturally from the new origin.
Transfers unreadChannels membership only if oldId was already unread
(mirror state, don't over-badge). Updates currentChannelId if it
matched oldId. Groundwork for DM origin failover rekey.
This commit is contained in:
Jannis Braun
2026-04-23 01:04:42 +02:00
parent e7430f1a54
commit d66932362a
2 changed files with 167 additions and 0 deletions
+39
View File
@@ -63,6 +63,7 @@ interface ChatState {
onChannelAck: (channelId: string, messageId: string) => void;
onMarkUnread: (channelId: string, messageId: string) => void;
removeChannelStates: (channelIds: Set<string>) => void;
rekeyChannelState: (oldId: string, newId: string) => void;
updateUserInMessages: (user: { id: string; [key: string]: any }) => void;
clearTypingForUser: (userId: string) => void;
}
@@ -708,6 +709,44 @@ export const useChatStore = create<ChatState>((set, get) => ({
});
},
rekeyChannelState: (oldId: string, newId: string) => {
set((state) => {
const copyDelete = <V,>(src: Map<string, V>): Map<string, V> => {
if (!src.has(oldId)) return src;
const next = new Map(src);
next.delete(oldId);
return next;
};
const messages = copyDelete(state.messages);
const typingUsers = copyDelete(state.typingUsers);
const hasMore = copyDelete(state.hasMore);
const readStates = copyDelete(state.readStates);
const channelAccessTimes = copyDelete(state.channelAccessTimes);
const scrollPositions = copyDelete(state.scrollPositions);
let unreadChannels = state.unreadChannels;
if (state.unreadChannels.has(oldId)) {
unreadChannels = new Set(state.unreadChannels);
unreadChannels.delete(oldId);
unreadChannels.add(newId);
}
const currentChannelId = state.currentChannelId === oldId ? newId : state.currentChannelId;
return {
messages,
typingUsers,
hasMore,
readStates,
channelAccessTimes,
scrollPositions,
unreadChannels,
currentChannelId,
};
});
},
updateUserInMessages: (user: { id: string; homeUserId?: string | null; [key: string]: any }) => {
set((state) => {
const newMessages = new Map(state.messages);