feat(presence): Redis-backed presence for multi-replica prod
Extract a PresencePort seam (async setFocus/clearSocket/isViewing) with two impls: the existing in-memory Map (dev, single instance) and a new RedisPresenceService (prod). MessageModule provides PRESENCE_PORT via a REDIS_URL-gated factory — same pattern as the socket.io Redis adapter — so 'who is viewing what' is shared across replicas and the notification projector's presence gate works at N>1. Gateway + projector inject the port; isViewing is now awaited. Presence spec updated to async (passing). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Presence seam: tracks which thread each socket has in the foreground so the notification
|
||||
* projector can suppress push for a thread the recipient is actively viewing. Async so it can be
|
||||
* backed by Redis across replicas (prod) or an in-memory Map on a single instance (dev).
|
||||
*/
|
||||
export interface PresencePort {
|
||||
/** Record a socket's foregrounded thread (null when the window is blurred / no thread open). */
|
||||
setFocus(socketId: string, userId: string, threadId: string | null): Promise<void>;
|
||||
/** Forget everything about a socket (on disconnect). */
|
||||
clearSocket(socketId: string): Promise<void>;
|
||||
/** True if ANY of the user's sockets currently has this thread in the foreground. */
|
||||
isViewing(userId: string, threadId: string): Promise<boolean>;
|
||||
}
|
||||
|
||||
export const PRESENCE_PORT = Symbol('PRESENCE_PORT');
|
||||
Reference in New Issue
Block a user