Files
Toju/toju-app/src/app/shared-kernel/chat-events.ts
2026-06-05 18:34:01 +02:00

535 lines
13 KiB
TypeScript

import type { Message, Reaction } from './message.models';
import type { MessageRevision } from './message-revision.models';
import type { UserRole, RoomMember } from './user.models';
import type {
Room,
RoomSettings,
RoomPermissions,
Channel
} from './room.models';
import type { VoiceState } from './voice-state.models';
import type { GameActivity } from './game-activity.models';
import type { BanEntry } from './moderation.models';
import type { ChatAttachmentAnnouncement, ChatAttachmentMeta } from './attachment-contracts';
import type {
CustomEmoji,
CustomEmojiSummaryItem,
CustomEmojiTransferManifest
} from './custom-emoji.models';
import type {
DirectMessageEventPayload,
DirectMessageMutationEventPayload,
DirectMessageSyncEventPayload,
DirectMessageSyncRequestEventPayload,
DirectMessageStatusEventPayload,
DirectMessageTypingEventPayload
} from './direct-message-contracts';
import type { DirectCallEventPayload } from './direct-call-contracts';
export interface ChatInventoryItem {
id: string;
ts: number;
rc: number;
ac?: number;
revision?: number;
headHash?: string;
}
// Every field that appears on any event is kept optional here so that
// code which accesses `event.roomId` etc. without narrowing first
// still compiles. Individual event interfaces below then make the
// relevant fields **required**.
export interface ChatEventBase {
fromPeerId?: string;
messageId?: string;
message?: Message;
reaction?: Reaction;
data?: string | Partial<Message>;
timestamp?: number;
targetUserId?: string;
roomId?: string;
items?: ChatInventoryItem[];
ids?: string[];
messages?: Message[];
attachments?: Record<string, ChatAttachmentMeta[]>;
total?: number;
index?: number;
count?: number;
lastUpdated?: number;
file?: ChatAttachmentAnnouncement;
fileId?: string;
username?: string;
hostId?: string;
hostOderId?: string;
previousHostId?: string;
previousHostOderId?: string;
kickedBy?: string;
bannedBy?: string;
content?: string;
editedAt?: number;
deletedAt?: number;
deletedBy?: string;
oderId?: string;
displayName?: string;
description?: string;
profileUpdatedAt?: number;
emoji?: string;
reason?: string;
settings?: Partial<RoomSettings>;
permissions?: Partial<RoomPermissions>;
voiceState?: Partial<VoiceState>;
gameActivity?: GameActivity | null;
isScreenSharing?: boolean;
isCameraEnabled?: boolean;
icon?: string;
iconUpdatedAt?: number;
avatarUrl?: string;
avatarHash?: string;
avatarMime?: string;
avatarUpdatedAt?: number;
role?: UserRole;
room?: Partial<Room>;
channels?: Channel[];
members?: RoomMember[];
ban?: BanEntry;
bans?: BanEntry[];
banOderId?: string;
expiresAt?: number;
directMessage?: DirectMessageEventPayload;
directMessageStatus?: DirectMessageStatusEventPayload;
directMessageMutation?: DirectMessageMutationEventPayload;
directMessageTyping?: DirectMessageTypingEventPayload;
directMessageSyncRequest?: DirectMessageSyncRequestEventPayload;
directMessageSync?: DirectMessageSyncEventPayload;
directCall?: DirectCallEventPayload;
pluginMessage?: unknown;
customEmoji?: CustomEmoji;
customEmojiTransfer?: CustomEmojiTransferManifest;
customEmojiSummaries?: CustomEmojiSummaryItem[];
customEmojiId?: string;
}
export interface ChatMessageEvent extends ChatEventBase {
type: 'message' | 'chat-message';
message: Message;
}
export interface MessageEditedEvent extends ChatEventBase {
type: 'edit' | 'message-edited';
messageId: string;
content: string;
editedAt: number;
}
export interface MessageDeletedEvent extends ChatEventBase {
type: 'delete' | 'message-deleted';
messageId: string;
}
export interface MessageRevisionEvent extends ChatEventBase {
type: 'message-revision';
revision: MessageRevision;
}
export interface ReactionAddedEvent extends ChatEventBase {
type: 'reaction' | 'reaction-added';
messageId: string;
reaction: Reaction;
}
export interface ReactionRemovedEvent extends ChatEventBase {
type: 'reaction-removed';
messageId: string;
oderId: string;
emoji: string;
}
export interface FileAnnounceChatEvent extends ChatEventBase {
type: 'file-announce';
messageId: string;
file: ChatAttachmentAnnouncement;
}
export interface FileChunkChatEvent extends ChatEventBase {
type: 'file-chunk';
messageId: string;
fileId: string;
index: number;
total: number;
data: string;
}
export interface FileRequestChatEvent extends ChatEventBase {
type: 'file-request';
messageId: string;
fileId: string;
}
export interface FileCancelChatEvent extends ChatEventBase {
type: 'file-cancel';
messageId: string;
fileId: string;
}
export interface FileNotFoundChatEvent extends ChatEventBase {
type: 'file-not-found';
messageId: string;
fileId: string;
}
export interface ChatInventoryRequestEvent extends ChatEventBase {
type: 'chat-inventory-request';
roomId: string;
}
export interface ChatInventoryEvent extends ChatEventBase {
type: 'chat-inventory';
roomId: string;
items: ChatInventoryItem[];
total: number;
}
export interface ChatSyncRequestIdsEvent extends ChatEventBase {
type: 'chat-sync-request-ids';
roomId: string;
ids: string[];
}
export interface ChatSyncBatchEvent extends ChatEventBase {
type: 'chat-sync-batch';
roomId: string;
messages: Message[];
}
export interface ChatSyncSummaryEvent extends ChatEventBase {
type: 'chat-sync-summary';
}
export interface ChatSyncRequestEvent extends ChatEventBase {
type: 'chat-sync-request';
roomId: string;
}
export interface ChatSyncFullEvent extends ChatEventBase {
type: 'chat-sync-full';
roomId: string;
messages: Message[];
}
export interface RoomDeletedEvent extends ChatEventBase {
type: 'room-deleted';
roomId: string;
}
export interface RoomSettingsUpdateEvent extends ChatEventBase {
type: 'room-settings-update';
roomId: string;
settings: Partial<RoomSettings>;
}
export interface RoomPermissionsUpdateEvent extends ChatEventBase {
type: 'room-permissions-update';
roomId: string;
permissions?: Partial<RoomPermissions>;
}
export interface HostChangeEvent extends ChatEventBase {
type: 'host-change';
roomId: string;
hostId: string;
hostOderId: string;
previousHostId: string;
previousHostOderId: string;
}
export interface VoiceStateEvent extends ChatEventBase {
type: 'voice-state';
voiceState: Partial<VoiceState>;
}
export interface VoiceChannelMoveEvent extends ChatEventBase {
type: 'voice-channel-move';
roomId: string;
targetUserId: string;
voiceState: Partial<VoiceState>;
}
export interface ScreenStateEvent extends ChatEventBase {
type: 'screen-state';
isScreenSharing: boolean;
}
export interface CameraStateEvent extends ChatEventBase {
type: 'camera-state';
isCameraEnabled: boolean;
}
export interface GameActivityEvent extends ChatEventBase {
type: 'game-activity';
gameActivity: GameActivity | null;
}
export interface VoiceStateRequestEvent extends ChatEventBase {
type: 'voice-state-request';
}
export interface StateRequestEvent extends ChatEventBase {
type: 'state-request';
}
export interface ScreenShareRequestEvent extends ChatEventBase {
type: 'screen-share-request';
}
export interface ScreenShareStopEvent extends ChatEventBase {
type: 'screen-share-stop';
}
export interface ServerIconSummaryEvent extends ChatEventBase {
type: 'server-icon-summary';
roomId: string;
iconUpdatedAt: number;
}
export interface ServerIconRequestEvent extends ChatEventBase {
type: 'server-icon-request';
roomId: string;
}
export interface ServerIconFullEvent extends ChatEventBase {
type: 'server-icon-full';
roomId: string;
icon?: string;
iconUpdatedAt: number;
}
export interface ServerIconUpdateEvent extends ChatEventBase {
type: 'server-icon-update';
roomId: string;
icon: string;
iconUpdatedAt: number;
}
export interface UserAvatarSummaryEvent extends ChatEventBase {
type: 'user-avatar-summary';
oderId: string;
username?: string;
displayName?: string;
description?: string;
profileUpdatedAt?: number;
avatarHash?: string;
avatarMime?: string;
avatarUpdatedAt: number;
}
export interface UserAvatarRequestEvent extends ChatEventBase {
type: 'user-avatar-request';
oderId: string;
}
export interface UserAvatarFullEvent extends ChatEventBase {
type: 'user-avatar-full';
oderId: string;
username?: string;
displayName?: string;
description?: string;
profileUpdatedAt?: number;
avatarHash?: string;
avatarMime?: string;
avatarUpdatedAt: number;
total: number;
}
export interface UserAvatarChunkEvent extends ChatEventBase {
type: 'user-avatar-chunk';
oderId: string;
avatarHash?: string;
avatarMime?: string;
avatarUpdatedAt?: number;
index: number;
total: number;
data: string;
}
export interface ServerStateRequestEvent extends ChatEventBase {
type: 'server-state-request';
roomId: string;
}
export interface ServerStateFullEvent extends ChatEventBase {
type: 'server-state-full';
roomId: string;
room: Partial<Room>;
}
export interface MemberRosterRequestEvent extends ChatEventBase {
type: 'member-roster-request';
roomId: string;
}
export interface MemberRosterEvent extends ChatEventBase {
type: 'member-roster';
roomId: string;
members: RoomMember[];
}
export interface MemberLeaveEvent extends ChatEventBase {
type: 'member-leave';
roomId: string;
}
export interface RoleChangeEvent extends ChatEventBase {
type: 'role-change';
}
export interface KickEvent extends ChatEventBase {
type: 'kick';
}
export interface BanEvent extends ChatEventBase {
type: 'ban';
}
export interface UnbanEvent extends ChatEventBase {
type: 'unban';
}
export interface ChannelsUpdateEvent extends ChatEventBase {
type: 'channels-update';
roomId: string;
channels: Channel[];
}
export interface DirectMessagePeerEvent extends ChatEventBase {
type: 'direct-message';
directMessage: DirectMessageEventPayload;
}
export interface DirectMessageStatusPeerEvent extends ChatEventBase {
type: 'direct-message-status';
directMessageStatus: DirectMessageStatusEventPayload;
}
export interface DirectMessageMutationPeerEvent extends ChatEventBase {
type: 'direct-message-mutation';
directMessageMutation: DirectMessageMutationEventPayload;
}
export interface DirectMessageTypingPeerEvent extends ChatEventBase {
type: 'direct-message-typing';
directMessageTyping: DirectMessageTypingEventPayload;
}
export interface DirectMessageSyncRequestPeerEvent extends ChatEventBase {
type: 'direct-message-sync-request';
directMessageSyncRequest: DirectMessageSyncRequestEventPayload;
}
export interface DirectMessageSyncPeerEvent extends ChatEventBase {
type: 'direct-message-sync';
directMessageSync: DirectMessageSyncEventPayload;
}
export interface DirectCallPeerEvent extends ChatEventBase {
type: 'direct-call';
directCall: DirectCallEventPayload;
}
export interface PluginMessageBusPeerEvent extends ChatEventBase {
type: 'plugin-message-bus';
pluginMessage: unknown;
}
export interface CustomEmojiSummaryEvent extends ChatEventBase {
type: 'custom-emoji-summary';
customEmojiSummaries: CustomEmojiSummaryItem[];
}
export interface CustomEmojiRequestEvent extends ChatEventBase {
type: 'custom-emoji-request';
ids: string[];
}
export interface CustomEmojiFullEvent extends ChatEventBase {
type: 'custom-emoji-full';
customEmoji?: CustomEmoji;
customEmojiTransfer?: CustomEmojiTransferManifest;
total?: number;
}
export interface CustomEmojiChunkEvent extends ChatEventBase {
type: 'custom-emoji-chunk';
customEmojiId: string;
index: number;
total: number;
data: string;
}
/** Discriminated union of all P2P chat events. Narrow via `event.type`. */
export type ChatEvent =
| ChatMessageEvent
| MessageEditedEvent
| MessageDeletedEvent
| MessageRevisionEvent
| ReactionAddedEvent
| ReactionRemovedEvent
| FileAnnounceChatEvent
| FileChunkChatEvent
| FileRequestChatEvent
| FileCancelChatEvent
| FileNotFoundChatEvent
| ChatInventoryRequestEvent
| ChatInventoryEvent
| ChatSyncRequestIdsEvent
| ChatSyncBatchEvent
| ChatSyncSummaryEvent
| ChatSyncRequestEvent
| ChatSyncFullEvent
| RoomDeletedEvent
| RoomSettingsUpdateEvent
| RoomPermissionsUpdateEvent
| HostChangeEvent
| VoiceStateEvent
| VoiceChannelMoveEvent
| ScreenStateEvent
| CameraStateEvent
| GameActivityEvent
| VoiceStateRequestEvent
| StateRequestEvent
| ScreenShareRequestEvent
| ScreenShareStopEvent
| UserAvatarSummaryEvent
| UserAvatarRequestEvent
| UserAvatarFullEvent
| UserAvatarChunkEvent
| ServerIconSummaryEvent
| ServerIconRequestEvent
| ServerIconFullEvent
| ServerIconUpdateEvent
| ServerStateRequestEvent
| ServerStateFullEvent
| MemberRosterRequestEvent
| MemberRosterEvent
| MemberLeaveEvent
| RoleChangeEvent
| KickEvent
| BanEvent
| UnbanEvent
| ChannelsUpdateEvent
| DirectMessagePeerEvent
| DirectMessageStatusPeerEvent
| DirectMessageMutationPeerEvent
| DirectMessageTypingPeerEvent
| DirectMessageSyncRequestPeerEvent
| DirectMessageSyncPeerEvent
| DirectCallPeerEvent
| PluginMessageBusPeerEvent
| CustomEmojiSummaryEvent
| CustomEmojiRequestEvent
| CustomEmojiFullEvent
| CustomEmojiChunkEvent;
/** All possible `type` values, derived from the union. */
export type ChatEventType = ChatEvent['type'];