import { Awareness } from "y-protocols/awareness"; import * as Y from "yjs"; import { type SyncEvent } from "../client/use-db-sync.js"; import { type CollabUser } from "./types.js"; export { dedupeCollabUsersByEmail, emailToColor, emailToName, type CollabUser, } from "./types.js"; export { isReconcileLeadClient } from "./lead-client.js"; export interface UseCollaborativeDocOptions { docId: string | null; pollInterval?: number; pollIntervalWithSse?: number; pauseWhenHidden?: boolean; baseUrl?: string; requestSource?: string; user?: CollabUser; activityResource?: { resourceType: string; resourceId: string; }; /** Application events received alongside document updates on the existing transport. */ onEvent?: (event: SyncEvent) => void; /** * Keeps this tab's unacknowledged updates in localStorage until the server * acknowledges them, and sends the ones a closed or reloaded tab left * behind when the doc next opens for the same user. Needs `user`, whose * email scopes what is kept. */ durableUpdates?: boolean; /** New updates need a known live-copy outcome handled by a current strict subscriber. */ requireLiveCopyOutcome?: boolean; /** * Called for each update the server acknowledged, with the live-copy * outcome it reported. With it, an acknowledgment whose body cannot be read * counts as undelivered and the update is sent again. */ onUpdateAcknowledged?: (ack: CollabUpdateAck) => void; } /** * What the server reported for an acknowledged update: whether the app's rows * were derived from its live copy, or null when the server defines none. */ export interface CollabUpdateAck { liveCopy: "derived" | "not_derived" | "unchanged" | null; liveCopyReason?: string; } export type CollabInitializationErrorCategory = "forbidden-or-not-found" | "server" | "network" | "invalid-payload"; export type CollabInitializationState = { status: "loading"; } | { status: "ready"; } | { status: "error"; category: CollabInitializationErrorCategory; }; export type CollaborativeDocSyncResult = { status: "synced"; } | { status: "failed"; error: Error; } | { status: "unavailable"; }; export interface UseCollaborativeDocResult { ydoc: Y.Doc | null; awareness: Awareness | null; isLoading: boolean; isSynced: boolean; initialization: CollabInitializationState; retry: () => void; requestSync: () => Promise; /** * Sends every local edit the server has not yet acknowledged. Resolves `true` * once none are outstanding and `false` when delivery failed (offline), so a * caller that saves the same content elsewhere can wait until collaborators * can already receive it through the document instead of inserting it twice. */ flushUpdates: () => Promise; /** * True once keeping this tab's unacknowledged updates, or reading the ones * another tab left, failed. Updates still send while the tab stays open. */ durableUpdatesFailed: boolean; /** * True once the server refused one of this tab's updates as too large. * Resending it cannot succeed, so this tab stops sending updates; they stay * unacknowledged, and kept with `durableUpdates`. */ updatesRefused: boolean; activeUsers: CollabUser[]; agentActive: boolean; 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;