wip: optimizations

This commit is contained in:
2026-05-23 15:28:40 +02:00
parent 5bf506af03
commit 155fe20862
89 changed files with 7431 additions and 392 deletions

25
electron/AGENTS.md Normal file
View File

@@ -0,0 +1,25 @@
# Electron Guidelines
This directory contains the Electron main process, preload bridge, IPC, desktop integration, and local persistence glue.
## Workflow
- Build with `npm run build:electron`.
- Use `npm run electron:dev` or `npm run dev` when you need the integrated desktop stack.
- See `../doc/typescript.md` for shared TypeScript rules.
## Boundaries
- Keep bootstrapping and lifecycle concerns in `app/`.
- Keep desktop platform integrations in focused modules such as `audio/`, `update/`, and `window/`.
- Keep renderer-exposed APIs typed in `preload.ts` and routed through explicit IPC handlers.
- When adding a new renderer-facing capability, update the Electron implementation, the preload surface, and the renderer bridge together.
- Keep persistence entities, migrations, and CQRS helpers aligned with the desktop database model rather than duplicating renderer types.
## Generated Output
- Treat `dist/electron/` and packaged artifacts in `dist-electron/` as build output, not source.
## Before You Finish
- Validate whether relevant markdown docs or `AGENTS.md` files need updates. If behavior, workflows, commands, or architecture changed, update those docs in the same task.

View File

@@ -0,0 +1,27 @@
import { DataSource } from 'typeorm';
import { MessageEntity } from '../../../entities';
import { GetRoomMessageStatsQuery } from '../../types';
import { getCurrentUserScope } from '../../current-user-scope';
export async function handleGetRoomMessageStats(query: GetRoomMessageStatsQuery, dataSource: DataSource) {
const repo = dataSource.getRepository(MessageEntity);
const { roomId } = query.payload;
const currentUserId = await getCurrentUserScope(dataSource);
if (!currentUserId) {
return { count: 0,
lastUpdated: 0 };
}
const row = await repo.createQueryBuilder('message')
.select('COUNT(message.id)', 'count')
.addSelect('MAX(COALESCE(message.editedAt, message.timestamp, 0))', 'lastUpdated')
.where('message.roomId = :roomId', { roomId })
.andWhere('message.ownerUserId = :currentUserId', { currentUserId })
.getRawOne<{ count?: string | number | null; lastUpdated?: string | number | null }>();
return {
count: Number(row?.count ?? 0) || 0,
lastUpdated: Number(row?.lastUpdated ?? 0) || 0
};
}

View File

@@ -5,6 +5,7 @@ import {
Query,
GetMessagesQuery,
GetMessagesSinceQuery,
GetRoomMessageStatsQuery,
GetMessageByIdQuery,
GetReactionsForMessageQuery,
GetUserQuery,
@@ -17,6 +18,7 @@ import {
} from '../types';
import { handleGetMessages } from './handlers/getMessages';
import { handleGetMessagesSince } from './handlers/getMessagesSince';
import { handleGetRoomMessageStats } from './handlers/getRoomMessageStats';
import { handleGetMessageById } from './handlers/getMessageById';
import { handleGetReactionsForMessage } from './handlers/getReactionsForMessage';
import { handleGetUser } from './handlers/getUser';
@@ -35,6 +37,7 @@ import { handleGetMeta } from './handlers/getMeta';
export const buildQueryHandlers = (dataSource: DataSource): Record<QueryTypeKey, (query: Query) => Promise<unknown>> => ({
[QueryType.GetMessages]: (query) => handleGetMessages(query as GetMessagesQuery, dataSource),
[QueryType.GetMessagesSince]: (query) => handleGetMessagesSince(query as GetMessagesSinceQuery, dataSource),
[QueryType.GetRoomMessageStats]: (query) => handleGetRoomMessageStats(query as GetRoomMessageStatsQuery, dataSource),
[QueryType.GetMessageById]: (query) => handleGetMessageById(query as GetMessageByIdQuery, dataSource),
[QueryType.GetReactionsForMessage]: (query) => handleGetReactionsForMessage(query as GetReactionsForMessageQuery, dataSource),
[QueryType.GetUser]: (query) => handleGetUser(query as GetUserQuery, dataSource),

View File

@@ -26,6 +26,7 @@ export type CommandTypeKey = typeof CommandType[keyof typeof CommandType];
export const QueryType = {
GetMessages: 'get-messages',
GetMessagesSince: 'get-messages-since',
GetRoomMessageStats: 'get-room-message-stats',
GetMessageById: 'get-message-by-id',
GetReactionsForMessage: 'get-reactions-for-message',
GetUser: 'get-user',
@@ -241,6 +242,7 @@ export interface GetMessagesQuery {
};
}
export interface GetMessagesSinceQuery { type: typeof QueryType.GetMessagesSince; payload: { roomId: string; sinceTimestamp: number } }
export interface GetRoomMessageStatsQuery { type: typeof QueryType.GetRoomMessageStats; payload: { roomId: string } }
export interface GetMessageByIdQuery { type: typeof QueryType.GetMessageById; payload: { messageId: string } }
export interface GetReactionsForMessageQuery { type: typeof QueryType.GetReactionsForMessage; payload: { messageId: string } }
export interface GetUserQuery { type: typeof QueryType.GetUser; payload: { userId: string } }
@@ -259,6 +261,7 @@ export interface GetMetaQuery { type: typeof QueryType.GetMeta; payload: { key:
export type Query =
| GetMessagesQuery
| GetMessagesSinceQuery
| GetRoomMessageStatsQuery
| GetMessageByIdQuery
| GetReactionsForMessageQuery
| GetUserQuery