/** * GroupService — manages group lifecycle, key management, and messaging. * * Maintains in-memory stores for groups and messages, with epoch-aware * symmetric key management via IKeyEpochState. Each key rotation creates * a new epoch. Messages record which epoch they were encrypted under. * On member removal, all epoch keys are re-wrapped for remaining members only. * * When an IChatStorageProvider is injected, groups and group 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.2, 5.1, 5.2, 5.3, 5.4, 9.3 */ import { Permission } from '../../enumerations/communication'; import { IChatAttachmentInput, ICommunicationMessage, 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'; import { MessageOperationsService } from './messageOperationsService'; import { PermissionService } from './permissionService'; export declare class GroupNotFoundError extends Error { constructor(groupId: string); } export declare class NotGroupMemberError extends Error { constructor(); } export declare class GroupMessageNotFoundError extends Error { constructor(messageId: string); } export declare class GroupPermissionError extends Error { readonly missingPermission: Permission; constructor(permission: Permission); } export declare class MemberMutedError extends Error { constructor(); } export declare class NotMessageAuthorError extends Error { constructor(); } export declare class ReactionNotFoundError extends Error { constructor(reactionId: string); } export declare class MemberAlreadyInGroupError extends Error { constructor(memberId: string); } /** * Callback for encrypting a symmetric key for a specific member. * In production this would use ECIES with the member's public key. * Returns the encrypted key as a string (e.g. base64). */ export type KeyEncryptionHandler = (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 extractKeyFromDefault(encrypted: string): Uint8Array; export declare class GroupService { /** groupId → IGroup */ private readonly groups; /** groupId → messages (ordered by createdAt ascending) */ private readonly messages; /** groupId → epoch-aware key state (raw keys + wrapped keys per epoch) */ private readonly keyEpochStates; private readonly permissionService; private readonly encryptKey; private readonly messageOps; private readonly eventEmitter; private readonly randomBytesProvider; /** Optional persistent collection for groups (write-through). */ private readonly groupCollection; /** Optional persistent collection for group messages (write-through). */ private readonly groupMessageCollection; /** Optional block content store for storing message content as blocks. */ private readonly blockContentStore; /** Whether init() has already been called (idempotency guard). */ private initialized; constructor(permissionService: PermissionService, encryptKey?: KeyEncryptionHandler, messageOps?: MessageOperationsService, eventEmitter?: ICommunicationEventEmitter, randomBytesProvider?: (length: number) => Uint8Array, storageProvider?: IChatStorageProvider, blockContentStore?: IBlockContentStore); /** * Load persisted groups and group messages back into in-memory Maps. * * Idempotent: only the first call performs rehydration. No-op when no * storage provider was supplied at construction time. * * Requirements: 1.2, 1.5, 1.6, 3.1, 3.2, 3.3, 3.4, 3.5, 8.1, 8.2, 8.3, 9.1, 9.4 */ init(): Promise; private assertGroupExists; private assertIsMember; private assertPermission; private assertNotMuted; 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 */ private assertEpochExists; /** * Create initial epoch state (epoch 0) for a new group. * Uses KeyEpochManager pattern: creates epoch 0 with wrapped keys for all members. * * Requirements: 5.1 */ private createInitialEpochState; /** * Add a member to an existing epoch state: wrap ALL epoch keys for the new member. * This gives the new member access to full message history. * * Requirements: 5.2 */ private addMemberToEpochState; /** * Rotate key: increment epoch, add new key, delete removed member from ALL epochs, * re-wrap ALL epoch keys for remaining members. * * Requirements: 5.3 */ private rotateEpochState; /** * Rotate the group's symmetric key using epoch-aware key management. * Generates a new key, increments epoch, re-wraps all epoch keys for remaining members, * and removes the departed member from all epochs. * * Requirements: 5.3 */ private rotateKey; /** * Create a new group with the given members. * Generates a shared symmetric key and encrypts it for each member. * The creator is assigned the OWNER role; others get MEMBER. * Uses KeyEpochManager pattern to create initial epoch 0. * * Requirements: 10.2, 5.1, 9.3 */ createGroup(name: string, creatorId: string, memberIds: string[]): Promise; /** * Create a group from a promoted conversation, preserving message history. * Generates a FRESH CEK (not reusing the DM key) per Requirement 5.4. * Used by ConversationService.promoteToGroup. */ createGroupFromConversation(conversationId: string, existingParticipants: [string, string], newMemberIds: string[], existingMessages: ICommunicationMessage[], requesterId: string): Promise; /** * Get group metadata. */ getGroup(groupId: string, requesterId: string): Promise; /** * Send a message to a group. * Encrypts content with the current epoch's CEK and records the keyEpoch. * Optionally accepts attachments which are validated against platform limits. * * Requirements: 10.2, 9.3, 11.1, 11.2, 11.4, 11.5 */ sendMessage(groupId: string, senderId: string, content: string, attachments?: IChatAttachmentInput[]): Promise; /** * Get messages in a group with cursor-based pagination. * Messages are returned with their keyEpoch so clients can decrypt * using the appropriate epoch's CEK. * Validates that each message's keyEpoch exists in the epoch state; * throws KeyEpochNotFoundError if a message references a non-existent epoch. * * Requirements: 5.1, 12.3 */ getMessages(groupId: string, memberId: string, cursor?: string, limit?: number): Promise>; /** * Add members to a group. Wraps ALL epoch keys for new members. * Requirements: 10.2, 5.2 */ addMembers(groupId: string, requesterId: string, memberIds: string[]): Promise; /** * Remove a member from a group. Rotates the shared key using epoch-aware rotation. * Requirements: 10.2, 5.3 */ removeMember(groupId: string, requesterId: string, targetId: string): Promise; /** * Leave a group voluntarily. Rotates the shared key using epoch-aware rotation. * Requirements: 10.2, 5.3 */ leaveGroup(groupId: string, memberId: string): Promise; /** * Edit a message authored by the requesting member. * Delegates to MessageOperationsService. */ editMessage(groupId: string, messageId: string, memberId: string, newContent: string): Promise; /** * Delete a message. Authors can delete their own; moderators/admins can delete any. * Delegates to MessageOperationsService. */ deleteMessage(groupId: string, messageId: string, memberId: string): Promise; /** * Pin a message in a group. * Delegates to MessageOperationsService. */ pinMessage(groupId: string, messageId: string, memberId: string): Promise; /** * Unpin a message in a group. * Delegates to MessageOperationsService. */ unpinMessage(groupId: string, messageId: string, memberId: string): Promise; /** * Add a reaction to a message. * Delegates to MessageOperationsService. */ addReaction(groupId: string, messageId: string, memberId: string, emoji: string): Promise; /** * Remove a reaction from a message. * Delegates to MessageOperationsService. */ removeReaction(groupId: string, messageId: string, memberId: string, reactionId: string): Promise; /** * Get a group by ID without membership check. Returns undefined if not found. */ getGroupById(groupId: string): IGroup | undefined; /** * Get the current epoch's raw symmetric key for a group. * Returns the key for the latest epoch (backward-compatible accessor). */ getSymmetricKey(groupId: string): Uint8Array | undefined; /** * Get the full epoch state for a group (testing / internal use). */ getKeyEpochState(groupId: string): IKeyEpochState | undefined; /** * Get all messages for a group without pagination (testing/internal). */ getAllMessages(groupId: string): ICommunicationMessage[]; /** * Return all groups the given member belongs to (no pagination). * Used by SearchService for cross-context keyword search. */ listGroupsForMember(memberId: string): IGroup[]; } //# sourceMappingURL=groupService.d.ts.map