feat: plugins v1.7

This commit is contained in:
2026-04-29 15:24:56 +02:00
parent eabbc08896
commit d261bac0ed
45 changed files with 5621 additions and 867 deletions

View File

@@ -2,6 +2,7 @@ import { Injectable, inject } from '@angular/core';
import { Store } from '@ngrx/store';
import { Subscription } from 'rxjs';
import { RealtimeSessionFacade } from '../../../../core/realtime';
import { DatabaseService } from '../../../../infrastructure/persistence';
import { VoiceConnectionFacade } from '../../../voice-connection/application/facades/voice-connection.facade';
import type {
Channel,
@@ -40,6 +41,7 @@ import { PluginUiRegistryService } from './plugin-ui-registry.service';
@Injectable({ providedIn: 'root' })
export class PluginClientApiService {
private readonly capabilities = inject(PluginCapabilityService);
private readonly db = inject(DatabaseService);
private readonly logger = inject(PluginLoggerService);
private readonly messageBus = inject(PluginMessageBusService);
private readonly realtime = inject(RealtimeSessionFacade);
@@ -159,11 +161,11 @@ export class PluginClientApiService {
messages: {
delete: (messageId) => {
requireCapability('messages.deleteOwn');
this.deletePluginMessage(messageId);
this.deletePluginMessage(pluginId, messageId);
},
edit: (messageId, content) => {
requireCapability('messages.editOwn');
this.editPluginMessage(messageId, content);
this.editPluginMessage(pluginId, messageId, content);
},
moderateDelete: (messageId) => {
requireCapability('messages.moderate');
@@ -175,7 +177,7 @@ export class PluginClientApiService {
},
send: (content, channelId) => {
requireCapability('messages.send');
return this.sendPluginMessage(content, channelId);
return this.sendPluginMessage(pluginId, content, channelId);
},
sendAsPluginUser: (request) => {
requireCapability('messages.send');
@@ -481,11 +483,18 @@ export class PluginClientApiService {
};
this.logger.info(pluginId, 'Plugin user message emitted', { messageId: message.id });
this.persistPluginMessage(pluginId, message);
this.store.dispatch(MessagesActions.receiveMessage({ message }));
this.voice.broadcastMessage({ type: 'chat-message', message } as unknown as ChatEvent);
}
private deletePluginMessage(messageId: string): void {
private deletePluginMessage(pluginId: string, messageId: string): void {
this.persistPluginMessageUpdate(pluginId, messageId, {
content: '[Message deleted]',
editedAt: Date.now(),
isDeleted: true
});
this.store.dispatch(MessagesActions.deleteMessageSuccess({ messageId }));
this.voice.broadcastMessage({
deletedAt: Date.now(),
@@ -494,9 +503,11 @@ export class PluginClientApiService {
} as unknown as ChatEvent);
}
private editPluginMessage(messageId: string, content: string): void {
private editPluginMessage(pluginId: string, messageId: string, content: string): void {
const editedAt = Date.now();
this.persistPluginMessageUpdate(pluginId, messageId, { content, editedAt });
this.store.dispatch(MessagesActions.editMessageSuccess({
content,
editedAt,
@@ -511,7 +522,7 @@ export class PluginClientApiService {
} as unknown as ChatEvent);
}
private sendPluginMessage(content: string, channelId?: string): Message {
private sendPluginMessage(pluginId: string, content: string, channelId?: string): Message {
const currentUser = this.currentUser();
const roomId = this.requireRoomId();
const message: Message = {
@@ -526,12 +537,25 @@ export class PluginClientApiService {
timestamp: Date.now()
};
this.persistPluginMessage(pluginId, message);
this.store.dispatch(MessagesActions.sendMessageSuccess({ message }));
this.voice.broadcastMessage({ type: 'chat-message', message } as unknown as ChatEvent);
return message;
}
private persistPluginMessage(pluginId: string, message: Message): void {
void this.db.saveMessage(message).catch((error: unknown) => {
this.logger.warn(pluginId, 'Failed to persist plugin message', error);
});
}
private persistPluginMessageUpdate(pluginId: string, messageId: string, updates: Partial<Message>): void {
void this.db.updateMessage(messageId, updates).catch((error: unknown) => {
this.logger.warn(pluginId, 'Failed to persist plugin message update', error);
});
}
private rememberSubscription(pluginId: string, eventName: string) {
this.logger.info(pluginId, `Subscribed to ${eventName}`);