P14b: session chat (table + whispers) + saved campaign recap

- Sidebar gains tabs: Chat / Rolls / (GM) Recap. Chat supports table messages and
  private whispers (GM→player via a recipient picker; player→GM via a toggle).
  Server routes table to all and whispers to the target only (+server tests).
- Rolls + chat are persisted to a per-campaign session recap (Dexie v13 sessionLog
  table + sessionLogRepo); the GM's "Recap" tab shows it (survives reloads/sessions).
- wsSync: chat send/receive, optimistic local echo, persistLog for the GM.
- Realtime e2e: GM table message reaches the player; the player's reply reaches the GM.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-08 17:15:38 +02:00
parent 4cb834ad6c
commit e562a270d1
12 changed files with 259 additions and 44 deletions
+26
View File
@@ -222,6 +222,32 @@ export class RoomHub {
for (const p of room.players) p.send(msg); // players only; the GM already sees it locally
}
/** Table chat (to all) or a whisper. GM `to` = target player; player `to` set = whisper to GM. */
chat(socket: Sender, body: string, to?: string): void {
const conn = this.conns.get(socket);
const room = conn ? this.rooms.get(conn.roomId) : undefined;
if (!conn || !room) return;
room.lastActivity = this.now();
if (conn.role === 'gm') {
if (to) {
const msg = { t: 'chat', from: 'GM', body, scope: 'whisper' } as const;
for (const [s, c] of this.conns) if (c.roomId === room.roomId && c.playerId === to) s.send(msg);
} else {
const msg = { t: 'chat', from: 'GM', body, scope: 'table' } as const;
for (const p of room.players) p.send(msg);
}
} else {
const from = room.seats.get(conn.playerId)?.name ?? `Player ${conn.playerId.slice(0, 4)}`;
if (to) {
room.gm?.send({ t: 'chat', from, body, scope: 'whisper' });
} else {
const msg = { t: 'chat', from, body, scope: 'table' } as const;
room.gm?.send(msg);
for (const p of room.players) if (p !== socket) p.send(msg);
}
}
}
disconnect(socket: Sender): void {
const conn = this.conns.get(socket);
if (!conn) return;