import { StoreApi, UseBoundStore } from 'zustand'; /** * Sync message types */ export type SyncMessageType = 'STATE_UPDATE' | 'STATE_REQUEST' | 'STATE_RESPONSE' | 'LEADER_ELECTION' | 'LEADER_ANNOUNCE' | 'TAB_PING' | 'TAB_PONG' | 'HEARTBEAT'; /** * Sync message structure */ export interface SyncMessage { type: SyncMessageType; tabId: string; timestamp: number; payload?: { state?: Partial; keys?: string[]; leaderId?: string; priority?: number; }; } /** * Conflict resolution strategy */ export type ConflictStrategy = 'last-write-wins' | 'first-write-wins' | 'merge' | 'custom'; /** * Sync configuration */ export interface BroadcastSyncConfig { /** BroadcastChannel name (should be unique per app) */ channelName: string; /** State keys to synchronize (empty = sync all) */ syncKeys?: (keyof TState)[]; /** Keys to never sync (e.g., sensitive data) */ excludeKeys?: (keyof TState)[]; /** Throttle sync messages (ms) */ throttleMs?: number; /** Debounce sync messages (ms) */ debounceMs?: number; /** Conflict resolution strategy */ conflictStrategy?: ConflictStrategy; /** Custom conflict resolver */ customResolver?: (local: Partial, remote: Partial) => Partial; /** Enable leader election */ enableLeaderElection?: boolean; /** Leader heartbeat interval (ms) */ leaderHeartbeatMs?: number; /** Log sync events to console (dev only) */ debug?: boolean; /** Callback when sync state changes */ onSyncStateChange?: (state: 'connected' | 'disconnected' | 'leader' | 'follower') => void; /** Callback when remote update received */ onRemoteUpdate?: (keys: string[], source: string) => void; /** Filter function to determine if a state change should be synced */ shouldSync?: (prevState: TState, nextState: TState) => boolean; } /** * Sync instance interface */ export interface BroadcastSyncInstance { /** Start synchronization */ start: () => void; /** Stop synchronization */ stop: () => void; /** Check if sync is active */ isActive: () => boolean; /** Check if this tab is the leader */ isLeader: () => boolean; /** Get current tab ID */ getTabId: () => string; /** Request full state from other tabs */ requestState: () => void; /** Broadcast current state to other tabs */ broadcastState: (keys?: (keyof TState)[]) => void; /** Get connected tab count (approximate) */ getConnectedTabs: () => number; /** Force this tab to become leader */ forceLeader: () => void; } /** * Create a BroadcastChannel-based state synchronizer * * @param store - Zustand store to synchronize * @param config - Sync configuration * @returns Sync instance with control methods * * @example * ```typescript * const sync = createBroadcastSync(useStore, { * channelName: 'app-sync', * syncKeys: ['theme', 'locale', 'settings'], * throttleMs: 100, * debug: process.env.NODE_ENV === 'development', * }); * * // Start syncing * sync.start(); * * // Check leadership * if (sync.isLeader()) { * console.log('This tab is the leader'); * } * * // Stop syncing (e.g., on logout) * sync.stop(); * ``` */ export declare function createBroadcastSync(store: UseBoundStore>, config: BroadcastSyncConfig): BroadcastSyncInstance; /** * React hook for BroadcastSync * * @example * ```typescript * function App() { * const sync = useBroadcastSync(useStore, { * channelName: 'app-sync', * syncKeys: ['theme', 'locale'], * }); * * return ( *
*

Tab ID: {sync.getTabId()}

*

Is Leader: {sync.isLeader() ? 'Yes' : 'No'}

*
* ); * } * ``` */ export declare function useBroadcastSync(store: UseBoundStore>, config: BroadcastSyncConfig): BroadcastSyncInstance;