interface Query { queryKey: readonly unknown[]; state?: { error?: unknown; }; } interface QueryClient { invalidateQueries(opts?: { queryKey?: string[]; predicate?: (query: Query) => boolean; }, options?: { cancelRefetch?: boolean; }): unknown; isFetching?(filters?: { queryKey?: string[]; predicate?: (query: Query) => boolean; }): number; } export type SyncEvent = { version?: number; source?: string; type?: string; key?: string; requestSource?: string; [k: string]: unknown; }; /** * True for sync events that drive immediate, agent-initiated UI navigation * or interaction rather than passive data invalidation — app-state writes in * general (they back `["app-state"]` queries directly), and specifically the * `navigate` / `show-questions` / `__set_url__` app-state keys that * `invalidateForEvents` special-cases into their own query keys below. * * `useDbSync` batches ordinary invalidation-driving events (action/collab/db * change events) into one flush per `INVALIDATE_COALESCE_MS` so a chatty doc * doesn't refetch on every keystroke. That trade-off is wrong for these * events: agent-driven navigation, `set-url`, and guided-questions prompts * must land as close to instantly as possible, so any batch containing one * of these bypasses the coalesce window and flushes immediately instead. * * Exported as a small pure predicate so this classification is unit-testable * independent of the transport/timer plumbing around it. */ export declare function isInteractionCriticalSyncEvent(event: SyncEvent): boolean; /** @internal */ export declare function _resetSyncTransportRegistryForTests(): void; export interface SubscribeSyncEventsOptions { /** Receives every batch of change events (SSE push or poll). */ onEvents: (events: SyncEvent[], version: number | undefined) => void; /** Notified when the shared SSE connection opens/closes (and once on join). */ onSseStateChange?: (connected: boolean, capabilities?: readonly string[]) => void; pollUrl?: string; sseUrl?: string | false; pauseWhenHidden?: boolean; /** * Poll cadence this subscriber requests from the SHARED poll loop. The * transport uses the minimum across subscribers, so the defaults here are * deliberately high: subscribing must not speed up the shared poll — * useDbSync (mounted by every template root) already sets the pace. */ interval?: number; fallbackInterval?: number; } /** * Subscribe to the shared SSE + poll transport without the React Query * invalidation behavior of `useDbSync`. Use this instead of opening another * `EventSource` to `/_agent-native/events` — a browser tab should hold ONE * SSE connection no matter how many features listen to it (extra streams eat * the per-origin connection budget and starve data fetches, especially on * HTTP/1.1 dev servers). * * Returns an unsubscribe function. Safe to call only in browser contexts. */ export declare function subscribeSyncEvents(options: SubscribeSyncEventsOptions): () => void; /** * Hook that listens to /_agent-native/events for DB change events and * invalidates react-query caches when changes are detected. Falls back to * /_agent-native/poll so cross-process/serverless writes still show up. * * Works in all deployment environments (serverless, edge, long-lived server). * SSE is the fast path; polling is the safety net. * * @param options.queryClient - The react-query QueryClient instance * @param options.queryKeys - **Deprecated and ignored.** The hook uses * framework-owned fixed prefixes plus per-source change counters instead of * caller-supplied key lists. Kept in the type signature for backward * compatibility — existing call sites that still pass this option keep * working but the value has no effect. * @param options.pollUrl - Poll endpoint URL. Default: "/_agent-native/poll" * @param options.sseUrl - SSE endpoint URL. Default: "/_agent-native/events". * Pass false to disable SSE and use polling only. * @param options.onEvent - Optional callback for each change event * @param options.interval - Poll interval in ms. Default: 2000 * @param options.fallbackInterval - Poll interval while SSE is connected. * Default: 60000 * @param options.pauseWhenHidden - Pause sync while the tab is hidden. * Default: false. Hidden tabs keep SSE connected and poll no faster than * every 10 seconds while active; idle polling remains at 60 seconds. * @param options.ignoreSource - Skip events whose `requestSource` matches this * value. Use a per-tab ID so the UI ignores its own writes while still * picking up changes from other tabs, agents, and scripts. * @param options.actionInvalidatePredicate - Optional filter for the broad * compatibility invalidate triggered by `action` events. Use this to keep * expensive active queries on explicit-refresh semantics while still letting * normal source-versioned queries react through `useChangeVersion`. * @param options.suppressActionInvalidationFor - Action names whose sync events * should not invalidate all action queries. Use only for high-volume * background actions that perform their own narrow client invalidation. */ export declare function useDbSync(options?: { queryClient?: QueryClient; queryKeys?: string[]; pollUrl?: string; sseUrl?: string | false; /** @deprecated Use pollUrl instead */ eventsUrl?: string; onEvent?: (data: any) => void; interval?: number; fallbackInterval?: number; pauseWhenHidden?: boolean; ignoreSource?: string; actionInvalidatePredicate?: (query: Query) => boolean; suppressActionInvalidationFor?: string[]; }): void; /** @deprecated Use useDbSync instead */ export declare const useFileWatcher: typeof useDbSync; /** * Subscribe to `refresh-screen` events from the agent. Returns an integer * that increments every time the agent invokes the framework's `refresh-screen` * tool. Apply it as a React `key` on the main content wrapper (the part * OUTSIDE the agent chat sidebar) so that region remounts and re-fetches its * data while the chat, sidebar, and any other persistent chrome keep their * in-flight state. * * Usage in a template's root: * * const screenKey = useScreenRefreshKey(); * return ( * *
* *
*
* ); */ export declare function useScreenRefreshKey(options?: { pollUrl?: string; sseUrl?: string | false; interval?: number; fallbackInterval?: number; pauseWhenHidden?: boolean; }): number; export {}; //# sourceMappingURL=use-db-sync.d.ts.map