fix: Improve plugin ui entry points, Fix chat scroll, fix notifications, fix user rights

This commit is contained in:
2026-05-17 16:09:16 +02:00
parent 8e3ccf4157
commit 8631290c01
35 changed files with 1560 additions and 619 deletions

View File

@@ -96,6 +96,7 @@ export interface IncomingMessageContext {
debugging: DebuggingService;
currentUser: User | null;
currentRoom: Room | null;
savedRooms?: Room[];
}
/** Signature for an incoming-message handler function. */
@@ -110,11 +111,12 @@ type MessageHandler = (
*/
function handleInventoryRequest(
event: IncomingMessageEvent,
{ db, webrtc, attachments }: IncomingMessageContext
ctx: IncomingMessageContext
): Observable<Action> {
const { db, webrtc, attachments } = ctx;
const { roomId, fromPeerId } = event;
if (!roomId || !fromPeerId)
if (!roomId || !fromPeerId || !isKnownRoomId(roomId, ctx))
return EMPTY;
return from(
@@ -155,11 +157,12 @@ function handleInventoryRequest(
*/
function handleInventory(
event: IncomingMessageEvent,
{ db, webrtc, attachments }: IncomingMessageContext
ctx: IncomingMessageContext
): Observable<Action> {
const { db, webrtc, attachments } = ctx;
const { roomId, fromPeerId, items } = event;
if (!roomId || !Array.isArray(items) || !fromPeerId)
if (!roomId || !Array.isArray(items) || !fromPeerId || !isKnownRoomId(roomId, ctx))
return EMPTY;
return from(
@@ -197,11 +200,12 @@ function handleInventory(
*/
function handleSyncRequestIds(
event: IncomingMessageEvent,
{ db, webrtc, attachments }: IncomingMessageContext
ctx: IncomingMessageContext
): Observable<Action> {
const { db, webrtc, attachments } = ctx;
const { roomId, ids, fromPeerId } = event;
if (!Array.isArray(ids) || !fromPeerId)
if (!roomId || !Array.isArray(ids) || !fromPeerId || !isKnownRoomId(roomId, ctx))
return EMPTY;
return from(
@@ -210,7 +214,7 @@ function handleSyncRequestIds(
(ids as string[]).map((id) => db.getMessageById(id))
);
const messages = maybeMessages.filter(
(msg): msg is Message => !!msg
(msg): msg is Message => !!msg && msg.roomId === roomId
);
const hydrated = await Promise.all(
messages.map((msg) => hydrateMessage(msg, db))
@@ -250,19 +254,26 @@ function handleSyncRequestIds(
*/
function handleSyncBatch(
event: IncomingMessageEvent,
{ db, attachments }: IncomingMessageContext
ctx: IncomingMessageContext
): Observable<Action> {
if (!hasMessageBatch(event))
return EMPTY;
if (hasAttachmentMetaMap(event.attachments)) {
const scopedEvent = scopeMessageBatchToKnownRooms(event, ctx);
if (!scopedEvent)
return EMPTY;
const { db, attachments } = ctx;
if (hasAttachmentMetaMap(scopedEvent.attachments)) {
attachments.registerSyncedAttachments(
event.attachments,
Object.fromEntries(event.messages.map((message) => [message.id, message.roomId]))
scopedEvent.attachments,
Object.fromEntries(scopedEvent.messages.map((message) => [message.id, message.roomId]))
);
}
return from(processSyncBatch(event, db, attachments)).pipe(
return from(processSyncBatch(scopedEvent, db, attachments)).pipe(
mergeMap((toUpsert) =>
toUpsert.length > 0
? of(MessagesActions.syncMessages({ messages: toUpsert }))
@@ -316,18 +327,22 @@ function queueWatchedAttachmentDownloads(
/** Saves an incoming chat message to DB and dispatches receiveMessage. */
function handleChatMessage(
event: IncomingMessageEvent,
{
ctx: IncomingMessageContext
): Observable<Action> {
const {
db,
debugging,
attachments,
currentUser
}: IncomingMessageContext
): Observable<Action> {
} = ctx;
const msg = event.message;
if (!msg)
return EMPTY;
if (!isKnownRoomId(msg.roomId, ctx))
return EMPTY;
// Skip our own messages (reflected via server relay)
const isOwnMessage =
msg.senderId === currentUser?.id ||
@@ -536,11 +551,12 @@ function handleFileNotFound(
*/
function handleSyncSummary(
event: IncomingMessageEvent,
{ db, webrtc, currentRoom }: IncomingMessageContext
ctx: IncomingMessageContext
): Observable<Action> {
const { db, webrtc, currentRoom } = ctx;
const targetRoomId = event.roomId || currentRoom?.id;
if (!targetRoomId)
if (!targetRoomId || !isKnownRoomId(targetRoomId, ctx))
return EMPTY;
return from(
@@ -575,12 +591,13 @@ function handleSyncSummary(
/** Responds to a peer's full sync request by sending all local messages. */
function handleSyncRequest(
event: IncomingMessageEvent,
{ db, webrtc, currentRoom }: IncomingMessageContext
ctx: IncomingMessageContext
): Observable<Action> {
const { db, webrtc, currentRoom } = ctx;
const targetRoomId = event.roomId || currentRoom?.id;
const fromPeerId = event.fromPeerId;
if (!targetRoomId || !fromPeerId)
if (!targetRoomId || !fromPeerId || !isKnownRoomId(targetRoomId, ctx))
return EMPTY;
return from(
@@ -600,12 +617,17 @@ function handleSyncRequest(
/** Merges a full message dump from a peer into the local DB and store. */
function handleSyncFull(
event: IncomingMessageEvent,
{ db, attachments }: IncomingMessageContext
ctx: IncomingMessageContext
): Observable<Action> {
if (!hasMessageBatch(event))
return EMPTY;
return from(processSyncBatch(event, db, attachments)).pipe(
const scopedEvent = scopeMessageBatchToKnownRooms(event, ctx);
if (!scopedEvent)
return EMPTY;
return from(processSyncBatch(scopedEvent, ctx.db, ctx.attachments)).pipe(
mergeMap((toUpsert) =>
toUpsert.length > 0
? of(MessagesActions.syncMessages({ messages: toUpsert }))
@@ -657,6 +679,49 @@ export function dispatchIncomingMessage(
return handler ? handler(event, ctx) : EMPTY;
}
function isKnownRoomId(roomId: string | undefined, ctx: IncomingMessageContext): boolean {
if (!roomId) {
return false;
}
return ctx.currentRoom?.id === roomId || (ctx.savedRooms ?? []).some((room) => room.id === roomId);
}
function scopeMessageBatchToKnownRooms(
event: SyncBatchEvent,
ctx: IncomingMessageContext
): SyncBatchEvent | null {
if (event.roomId && !isKnownRoomId(event.roomId, ctx)) {
return null;
}
const messages = event.messages.filter((message) => isKnownRoomId(message.roomId, ctx));
if (messages.length === 0) {
return null;
}
return {
...event,
attachments: filterAttachmentMapToMessages(event.attachments, messages),
messages
};
}
function filterAttachmentMapToMessages(
attachmentMap: IncomingMessageEvent['attachments'],
messages: Message[]
): AttachmentMetaMap | undefined {
if (!hasAttachmentMetaMap(attachmentMap)) {
return undefined;
}
const messageIds = new Set(messages.map((message) => message.id));
const filteredEntries = Object.entries(attachmentMap).filter(([messageId]) => messageIds.has(messageId));
return filteredEntries.length > 0 ? Object.fromEntries(filteredEntries) : undefined;
}
function trackBackgroundOperation(
task: Promise<unknown> | unknown,
debugging: DebuggingService,