feat: DM infrastructure overhaul + volume sliders + LiveKit dynamic URL

- Add DM edit/delete endpoints (REST + WebSocket)
- Add DM typing indicators with real-time broadcast
- Fix volume sliders to control LiveKit mic/speaker
- Fix Send Message button on user profile popout
- Add New DM modal with user search
- Fix message pagination (SQL cursor instead of in-memory)
- Guard optional attachments on DM messages
- Dynamic LiveKit URL from request Host header
- DM sidebar auto-sorts by most recent message
This commit is contained in:
Jannis Braun
2026-02-18 17:29:39 +01:00
parent 4f65ea9c86
commit 7168149d98
31 changed files with 1189 additions and 136 deletions
+11
View File
@@ -58,6 +58,7 @@ export const messages = sqliteTable('messages', {
export const attachments = sqliteTable('attachments', {
id: text('id').primaryKey(),
messageId: text('message_id').references(() => messages.id, { onDelete: 'cascade' }),
dmMessageId: text('dm_message_id'),
filename: text('filename').notNull(),
originalName: text('original_name').notNull(),
mimetype: text('mimetype').notNull(),
@@ -81,7 +82,9 @@ export const dmMessages = sqliteTable('dm_messages', {
id: text('id').primaryKey(),
dmChannelId: text('dm_channel_id').notNull().references(() => dmChannels.id, { onDelete: 'cascade' }),
userId: text('user_id').notNull().references(() => users.id),
replyToId: text('reply_to_id'),
content: text('content'),
editedAt: integer('edited_at'),
createdAt: integer('created_at').notNull(),
});
@@ -109,6 +112,14 @@ export const reactions = sqliteTable('reactions', {
createdAt: integer('created_at').notNull(),
});
export const dmReactions = sqliteTable('dm_reactions', {
id: text('id').primaryKey(),
dmMessageId: text('dm_message_id').notNull(),
userId: text('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
emoji: text('emoji').notNull(),
createdAt: integer('created_at').notNull(),
});
export const roles = sqliteTable('roles', {
id: text('id').primaryKey(),
serverId: text('server_id').notNull().references(() => servers.id, { onDelete: 'cascade' }),