feat: Update how messages load and sync, allow plugins to import messages
Queue Release Build / prepare (push) Successful in 23s
Deploy Web Apps / deploy (push) Successful in 7m36s
Queue Release Build / build-windows (push) Successful in 28m3s
Queue Release Build / build-linux (push) Successful in 44m14s
Queue Release Build / finalize (push) Successful in 39s

This commit is contained in:
2026-05-18 23:21:09 +02:00
parent 94428ed170
commit 54e8b9a5e4
19 changed files with 542 additions and 86 deletions
@@ -13,10 +13,18 @@ export interface MessagesState extends EntityState<Message> {
loading: boolean;
/** Whether a peer-to-peer sync cycle is in progress. */
syncing: boolean;
/** Whether a scroll-up older-page fetch is currently in flight. */
loadingOlder: boolean;
/** Most recent error message from message operations. */
error: string | null;
/** ID of the room whose messages are currently loaded. */
currentRoomId: string | null;
/**
* Conversation keys (`${roomId}:${channelId}`) that have been paginated
* all the way back to the start of the local DB history. Used by the
* scroll-up handler to stop issuing further DB pages.
*/
exhaustedConversations: Record<string, true>;
}
export const messagesAdapter: EntityAdapter<Message> = createEntityAdapter<Message>({
@@ -27,8 +35,10 @@ export const messagesAdapter: EntityAdapter<Message> = createEntityAdapter<Messa
export const initialState: MessagesState = messagesAdapter.getInitialState({
loading: false,
syncing: false,
loadingOlder: false,
error: null,
currentRoomId: null
currentRoomId: null,
exhaustedConversations: {}
});
export const messagesReducer = createReducer(
@@ -41,7 +51,8 @@ export const messagesReducer = createReducer(
...state,
loading: true,
error: null,
currentRoomId: roomId
currentRoomId: roomId,
exhaustedConversations: {}
});
}
@@ -66,6 +77,30 @@ export const messagesReducer = createReducer(
error
})),
// Load older messages - paginate backwards from the DB on scroll-up.
on(MessagesActions.loadOlderMessages, (state) => ({
...state,
loadingOlder: true,
error: null
})),
on(MessagesActions.loadOlderMessagesSuccess, (state, { conversationKey, messages, reachedEnd }) =>
messagesAdapter.upsertMany(messages, {
...state,
loadingOlder: false,
exhaustedConversations: reachedEnd
? { ...state.exhaustedConversations,
[conversationKey]: true }
: state.exhaustedConversations
})
),
on(MessagesActions.loadOlderMessagesFailure, (state, { error }) => ({
...state,
loadingOlder: false,
error
})),
// Send message
on(MessagesActions.sendMessage, (state) => ({
...state,
@@ -202,7 +237,10 @@ export const messagesReducer = createReducer(
return messagesAdapter.upsertMany(merged, {
...state,
syncing: false
syncing: false,
// Peer sync may have inserted messages older than our current oldest;
// reopen pagination so the scroll-up handler revisits the DB.
exhaustedConversations: {}
});
}),
@@ -221,7 +259,8 @@ export const messagesReducer = createReducer(
on(MessagesActions.clearMessages, (state) =>
messagesAdapter.removeAll({
...state,
currentRoomId: null
currentRoomId: null,
exhaustedConversations: {}
})
)
);