/** * Client-side hook for collaborative document editing via Yjs. * * Creates a STABLE Y.Doc per docId that never changes identity. This allows * TipTap's Collaboration extension to bind once without editor recreation. * Server state is applied to the existing doc when it arrives. * * Also manages Yjs Awareness for cursor positions and user presence, * synced via polling to the server's awareness endpoint. * * Connection sharing: connections live in a module-level, ref-counted registry * keyed by docId (mirroring the SyncTransport registry in use-db-sync.ts). * Every `useCollaborativeDoc` mount for the same docId attaches to ONE shared * connection — one Y.Doc, one Awareness, one state fetch, one poll loop, one * awareness POST cycle — instead of each hook instance opening an independent * connection and doubling all collab traffic (e.g. a presence bar and the * editor mounting the hook for the same doc). The first subscriber starts the * connection; the last one leaving tears it down after a short linger so * StrictMode double-mounts and rapid unmount/remounts don't thrash the doc. * * Transport improvements (vs previous version): * - Local update POSTs are debounced and coalesced with Y.mergeUpdates (~80ms) * to avoid per-keystroke requests. The batch is flushed immediately on * visibilitychange/pagehide and before each poll/awareness cycle. * - GET state?stateVector= is NOT fetched on every poll cycle. It is fetched: * (a) on (re)connect / initial load, (b) when a poll response indicates a * gap (version jump > ring-buffer size), (c) after applying an update fails, * and (d) as a low-frequency safety net every STATE_VECTOR_FETCH_INTERVAL * poll cycles (~15×). * - Network errors use exponential backoff with jitter (cap ~15s), reset on * success. * - SSE fast-path: collab events are received push-style from * /_agent-native/events (the framework SSE stream). While SSE is * healthy the poll loop relaxes to a slow cadence (10–15s). If SSE is * unavailable the 2s poll resumes automatically. */ import { type CollabUser } from "@agent-native/toolkit/collab-ui"; import { Awareness } from "y-protocols/awareness"; import * as Y from "yjs"; export { dedupeCollabUsersByEmail, emailToColor, emailToName, isReconcileLeadClient, type CollabUser, } from "@agent-native/toolkit/collab-ui"; export interface UseCollaborativeDocOptions { /** Document ID to collaborate on. Pass null to disable. */ docId: string | null; /** Poll interval in ms when SSE is unavailable. Default: 2000 */ pollInterval?: number; /** Poll interval in ms while SSE is healthy. Default: 12000 */ pollIntervalWithSse?: number; /** Pause remote update/presence polling while the tab is hidden. Default: true */ pauseWhenHidden?: boolean; /** Base URL for collab endpoints. Default: "/_agent-native/collab" */ baseUrl?: string; /** Request source ID for jitter prevention (e.g., tab ID). */ requestSource?: string; /** Current user info for cursor labels. */ user?: CollabUser; } export interface UseCollaborativeDocResult { /** The Yjs document instance. Stable per docId — never changes identity. */ ydoc: Y.Doc | null; /** Yjs Awareness instance for cursor/presence sync. */ awareness: Awareness | null; /** Whether the initial state is still loading from the server. */ isLoading: boolean; /** Whether the doc is synced with the server. */ isSynced: boolean; /** Active users on this document (from awareness). */ activeUsers: CollabUser[]; /** True briefly when the AI agent makes an edit (for presence indicator). */ agentActive: boolean; /** True when the AI agent has an active awareness entry (durable presence). */ agentPresent: boolean; } export interface RemoteAwarenessSnapshot { clientId: number; state: unknown; } export declare function reconcileRemoteAwarenessStates(states: Map, localClientId: number, remoteStates: RemoteAwarenessSnapshot[]): { added: number[]; updated: number[]; removed: number[]; }; /** @internal */ export declare function _resetCollabDocRegistryForTests(): void; /** @internal — current registry size, for leak assertions in tests. */ export declare function _collabDocRegistrySizeForTests(): number; export declare function useCollaborativeDoc(options: UseCollaborativeDocOptions): UseCollaborativeDocResult; //# sourceMappingURL=client.d.ts.map