tests — presence

Module: tests-presence Cohesion: 0.80 Members: 0

tests — presence

This documentation describes the TypingIndicatorManager module, located at src/presence/typing-indicator.ts. While the provided source code is a test file (tests/presence/typing-indicator.test.ts), this document focuses on the functionality and API of the TypingIndicatorManager class itself, as inferred from its comprehensive test suite.


Module: TypingIndicatorManager

The TypingIndicatorManager is responsible for managing and broadcasting user typing activity across different channels and chats, as well as maintaining a global presence status for the application or user. It provides a unified way to signal when a user starts or stops typing, and automatically updates the overall presence based on active typing sessions.

Purpose

Key Concepts

  1. Typing Session: Represents a single instance of a user typing in a specific channel and chatId. Each session is identified by a unique key (channel:chatId).
  2. Typing Interval: When a typing session starts, the manager periodically re-emits a "typing" event to signal continued activity. This interval is configurable.
  3. Presence State: The manager maintains a global presence state (online or busy) and an optional currentTask string. This state reflects whether the user is actively engaged in typing or other tasks.

Usage Example

import { TypingIndicatorManager } from '../../src/presence/typing-indicator.js';

class="hl-cmt">// Initialize with a 4-second interval for repeated typing events
const typingManager = new TypingIndicatorManager(4000);

class="hl-cmt">// Listen for typing events
typingManager.on('typing', (data) => {
  console.log(`Typing event: ${data.channel}:${data.chatId} - typing: ${data.typing}`);
});

class="hl-cmt">// Listen for presence changes
typingManager.on('presence', (presence) => {
  console.log(`Presence updated: ${presence.status} - Task: ${presence.currentTask || 'None'}`);
});

class="hl-cmt">// Start typing in a Telegram chat
const telegramKey = typingManager.startTyping('telegram', 'chat123');
class="hl-cmt">// Output: Typing event: telegram:chat123 - typing: true
class="hl-cmt">// Output: Presence updated: busy - Task: None (or whatever was set manually)

console.log('Active typing sessions:', typingManager.getActiveCount()); class="hl-cmt">// 1
console.log('Current presence:', typingManager.getPresence()); class="hl-cmt">// { status: 'busy' }

class="hl-cmt">// Start typing in a Discord room
typingManager.startTyping('discord', 'room42');
class="hl-cmt">// Output: Typing event: discord:room42 - typing: true

console.log('Active typing sessions:', typingManager.getActiveCount()); class="hl-cmt">// 2

class="hl-cmt">// Simulate time passing (e.g., after 4 seconds)
class="hl-cmt">// typingManager will re-emit typing:true for both sessions

class="hl-cmt">// Stop typing in Telegram
typingManager.stopTyping(telegramKey);
class="hl-cmt">// Output: Typing event: telegram:chat123 - typing: false

console.log('Active typing sessions:', typingManager.getActiveCount()); class="hl-cmt">// 1
console.log('Current presence:', typingManager.getPresence()); class="hl-cmt">// { status: 'busy' } (still busy because Discord is active)

class="hl-cmt">// Manually update presence
typingManager.updatePresence('busy', 'processing query');
class="hl-cmt">// Output: Presence updated: busy - Task: processing query

class="hl-cmt">// Stop all remaining typing sessions
typingManager.stopAll();
class="hl-cmt">// Output: Typing event: discord:room42 - typing: false
class="hl-cmt">// Output: Presence updated: online - Task: None (or previous manual task if not cleared)

console.log('Active typing sessions:', typingManager.getActiveCount()); class="hl-cmt">// 0
console.log('Current presence:', typingManager.getPresence()); class="hl-cmt">// { status: 'online' }

class="hl-cmt">// Clean up resources
typingManager.dispose();

API Reference

The TypingIndicatorManager extends TypedEmitter, allowing it to emit and listen for specific events.

constructor(intervalMs: number)

Initializes a new TypingIndicatorManager instance.

startTyping(channel: string, chatId: string): string

Initiates a typing session for a specific channel and chat.

stopTyping(sessionKey: string): void

Stops a specific typing session.

stopAll(): void

Stops all active typing sessions managed by this instance.

getActiveCount(): number

Returns the number of currently active typing sessions.

getPresence(): { status: 'online' | 'busy', currentTask?: string }

Retrieves the current global presence status and any associated task.

updatePresence(status: 'online' | 'busy', currentTask?: string): void

Manually updates the global presence status and an optional task.

dispose(): void

Cleans up all resources associated with the TypingIndicatorManager.

Events

The TypingIndicatorManager emits the following events:

'typing'

Emitted when a typing session starts, stops, or continues.

'presence'

Emitted when the global presence status changes.

How It Works

The TypingIndicatorManager maintains an internal map of active typing sessions. Each entry in this map stores the channel, chatId, and a setInterval ID.

  1. startTyping:

  1. stopTyping:

  1. stopAll: Iterates through all active sessions and calls stopTyping for each.
  2. Presence Management: The status component of the global presence is automatically managed by startTyping and stopTyping based on the number of active typing sessions. updatePresence allows for manual overrides or setting of the currentTask.

Presence State Flow

graph TD
    A[Online] --> B{startTyping};
    B --> C[Busy];
    C -- interval --> C;
    C --> D{stopAll / last stopTyping};
    D --> A;
    C -- updatePresence --> C;
    A -- updatePresence --> A;

This diagram illustrates how the global presence state transitions. startTyping moves the state to Busy, and it remains Busy as long as any typing session is active. Only when all typing sessions are stopped (either individually or via stopAll) does the state revert to Online. updatePresence allows for modifying the currentTask or explicitly setting the status (though startTyping/stopTyping will still influence the status based on active sessions).