/** * ConversationService — manages direct message conversations and promotion to groups. * * Maintains in-memory stores for conversations and messages, delegating * encrypted content storage to MessagePassingService. Supports cursor-based * pagination, message deletion, and conversation promotion to groups. * * Uses epoch-aware key management via IKeyEpochState for forward secrecy. * DM conversations generate a 256-bit DM_Key at creation, wrapped per-participant * using the injected key encryption handler. Messages record the keyEpoch they * were encrypted under. * * When an IChatStorageProvider is injected, conversations and messages are * also persisted to the provider's collections (write-through). Sync helper * methods continue to read from the in-memory Maps so their signatures * remain unchanged. * * Requirements: 10.1, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 9.2 */ import { IChatAttachmentInput, ICommunicationMessage, IConversation, IGroup, IPaginatedResult } from '../../interfaces/communication'; import { IBlockContentStore } from '../../interfaces/communication/blockContentStore'; import { IChatStorageProvider } from '../../interfaces/communication/chatStorageProvider'; import { ICommunicationEventEmitter } from '../../interfaces/events'; import { IKeyEpochState } from './keyEpochManager'; /** * Callback for encrypting a symmetric key for a specific member. * Returns the encrypted key as a string (e.g. base64). */ export type ConversationKeyEncryptionHandler = (memberId: string, symmetricKey: Uint8Array) => string; /** * Extract the symmetric key from a default-encrypted key string. * Only works with the default placeholder encryption. */ export declare function extractConversationKeyFromDefault(encrypted: string): Uint8Array; /** * Callback to check whether a member exists and is not blocked by the sender. * Returns true if the member is reachable, false otherwise. * Used to produce uniform errors for non-existent and blocked members. */ export type MemberReachabilityCheck = (senderId: string, recipientId: string) => boolean; /** * Callback to promote a conversation to a group. * Injected from GroupService once it is available. * Returns the newly created IGroup. */ export type GroupPromotionHandler = (conversationId: string, existingParticipants: [string, string], newMemberIds: string[], messages: ICommunicationMessage[], requesterId: string) => Promise; /** * Uniform error thrown when a recipient is not reachable. * The message is intentionally identical for non-existent and blocked members * to prevent information leakage. */ export declare class RecipientNotReachableError extends Error { constructor(); } export declare class ConversationNotFoundError extends Error { constructor(conversationId: string); } export declare class NotParticipantError extends Error { constructor(); } export declare class MessageNotFoundError extends Error { constructor(messageId: string); } export declare class NotMessageAuthorError extends Error { constructor(); } export declare class GroupPromotionNotConfiguredError extends Error { constructor(); } export declare class ConversationService { /** conversationId → IConversation */ private readonly conversations; /** conversationId → messages (ordered by createdAt ascending) */ private readonly messages; /** "memberA:memberB" (sorted) → conversationId for dedup */ private readonly participantIndex; /** Set of blocked pairs: "blocker:blocked" */ private readonly blockedPairs; /** Set of known member IDs */ private readonly knownMembers; /** conversationId → epoch-aware key state (raw keys + wrapped keys per epoch) */ private readonly keyEpochStates; private groupPromotionHandler; private initialized; private readonly memberReachabilityCheck; private readonly eventEmitter; private readonly encryptKey; private readonly randomBytesProvider; /** Optional persistent collection for conversations (write-through). */ private readonly conversationCollection; /** Optional persistent collection for messages (write-through). */ private readonly messageCollection; /** Optional block content store for storing message content as blocks. */ private readonly blockContentStore; constructor(memberReachabilityCheck?: MemberReachabilityCheck | null, eventEmitter?: ICommunicationEventEmitter, storageProvider?: IChatStorageProvider, encryptKey?: ConversationKeyEncryptionHandler, randomBytesProvider?: (length: number) => Uint8Array, blockContentStore?: IBlockContentStore); /** * Load persisted conversations and messages from the storage provider * into in-memory Maps, rebuilding derived indexes and key epoch states. * * No-op when no storage provider was injected or when already initialized. * * Requirements: 1.1, 1.5, 1.6, 2.1, 2.2, 2.3, 2.4, 2.5, 8.1, 8.2, 8.3, 9.1, 9.2 */ init(): Promise; private generateSymmetricKey; /** * Encrypt a symmetric key for multiple members, returning a Map. * Wraps key wrapping failures as KeyUnwrapError with context information. * * Requirements: 12.3 */ private encryptKeyForMembers; /** * Assert that a key epoch exists in the epoch state for a given context. * Throws KeyEpochNotFoundError if the epoch is not found. * * Requirements: 12.3, 12.4 */ private assertEpochExists; /** * Create initial epoch state (epoch 0) for a new conversation. * Uses KeyEpochManager pattern: creates epoch 0 with wrapped keys for all participants. * * Requirements: 4.1, 4.4 */ private createInitialEpochState; /** * Register a member as known (exists in the system). */ registerMember(memberId: string): void; /** * Block a member. The blocker will not receive messages from the blocked member. */ blockMember(blockerId: string, blockedId: string): void; /** * Set the handler for promoting conversations to groups. * Called during initialization once GroupService is available. */ setGroupPromotionHandler(handler: GroupPromotionHandler): void; /** * Check if a recipient is reachable by the sender. * Returns false for non-existent or blocked members. */ private isReachable; /** * Build a sorted participant key for dedup lookups. */ private participantKey; /** * Create a new conversation between two members, or return the existing one. * Generates a DM_Key and wraps for both participants using epoch-aware key management. * * Requirements: 4.1, 4.4, 9.2 */ createOrGetConversation(memberA: string, memberB: string): Promise; /** * List conversations for a member, sorted by lastMessageAt descending. * Supports cursor-based pagination. */ listConversations(memberId: string, cursor?: string, limit?: number): Promise>; /** * Get messages in a conversation, in chronological order. * Messages are returned with their keyEpoch so clients can decrypt * using the appropriate epoch's DM_Key. * Validates that each message's keyEpoch exists in the epoch state; * throws KeyEpochNotFoundError if a message references a non-existent epoch. * Supports cursor-based pagination. * * Requirements: 4.3, 4.5, 12.3, 12.4 */ getMessages(conversationId: string, memberId: string, cursor?: string, limit?: number): Promise>; /** * Send a message in a conversation. * Creates the conversation if it doesn't exist. * Encrypts content with the current epoch's DM_Key and records the keyEpoch. * Checks recipient reachability and returns a uniform error for * non-existent or blocked members. * Optionally accepts attachments which are validated against platform limits. * * Requirements: 4.2, 4.5, 9.2, 11.1, 11.2, 11.4, 11.5 */ sendMessage(senderId: string, recipientId: string, content: string, conversationId?: string, attachments?: IChatAttachmentInput[]): Promise; /** * Delete a message authored by the requesting member. * Marks the message as deleted for all participants. */ deleteMessage(conversationId: string, messageId: string, memberId: string): Promise; /** * Promote a conversation to a group by adding new members. * Delegates to the GroupPromotionHandler (wired from GroupService). */ promoteToGroup(conversationId: string, newMemberIds: string[], requesterId: string): Promise; /** * Get a conversation by ID. Returns undefined if not found. */ getConversation(conversationId: string): IConversation | undefined; /** * Get the current epoch's raw symmetric key for a conversation. * Returns the key for the latest epoch (backward-compatible accessor). */ getSymmetricKey(conversationId: string): Uint8Array | undefined; /** * Get the full epoch state for a conversation (testing / internal use). */ getKeyEpochState(conversationId: string): IKeyEpochState | undefined; /** * Get all messages for a conversation (no pagination). Used internally * for promotion and testing. */ getAllMessages(conversationId: string): ICommunicationMessage[]; /** * Return all conversations that include the given member (no pagination). * Used by SearchService for cross-context keyword search. */ listAllConversationsForMember(memberId: string): IConversation[]; } //# sourceMappingURL=conversationService.d.ts.map