/** Maximum number of messages to include in sync inventories. * * The inventory protocol now ships every message in the room (id, ts, rc, ac) * chunked at `CHUNK_SIZE`, so peers converge on the full history regardless * of how lopsided their message counts are. The constant remains as a safety * ceiling for pathological rooms. */ export const INVENTORY_LIMIT = 1_000_000; /** Number of messages per chunk for inventory / batch transfers. */ export const CHUNK_SIZE = 200; /** Aggressive sync poll interval (10 seconds). */ export const SYNC_POLL_FAST_MS = 10_000; /** Idle sync poll interval after a clean (no-new-messages) cycle (15 minutes). */ export const SYNC_POLL_SLOW_MS = 900_000; /** Sync timeout duration before auto-completing a cycle (5 seconds). */ export const SYNC_TIMEOUT_MS = 5_000; /** Large limit used for legacy full-sync operations. */ export const FULL_SYNC_LIMIT = 1_000_000; /** Inventory item representing a message's sync state. */ export interface InventoryItem { id: string; ts: number; rc: number; ac?: number; } /** Splits an array into chunks of the given size. */ export function chunkArray(items: T[], size: number): T[][] { const chunks: T[][] = []; for (let index = 0; index < items.length; index += size) { chunks.push(items.slice(index, index + size)); } return chunks; } /** Identifies missing or stale message IDs by comparing remote items against a local map. */ export function findMissingIds( remoteItems: readonly { id: string; ts: number; rc?: number; ac?: number }[], localMap: ReadonlyMap ): string[] { const missing: string[] = []; for (const item of remoteItems) { const local = localMap.get(item.id); if ( !local || item.ts > local.ts || (item.rc !== undefined && item.rc !== local.rc) || (item.ac !== undefined && item.ac !== local.ac) ) { missing.push(item.id); } } return missing; }