import * as redux from 'redux'; import { JSONObject, JSONValue, Logger, ReducerFn } from './types.js'; declare global { interface Window { __REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof redux.compose; } } interface ReduxAction extends JSONObject { redux_type: string; type: string; payload: JSONValue; } type SaveStatus = 'saved' | 'modified' | 'error'; /** * A fatal, sticky condition surfaced by a logger (currently websocketLogger's * requireAck mis-deploy: ACK_REQUIRED). Null = no fatal. Sticky until the * logger clears it (e.g. a late ack-capable hello recovers the connection). */ type FatalState = { code: string; message: string; } | null; /** * Options for the Redux logger's persistence behavior. * * serializeForSave: Called before every save (server and localStorage). * Receives the full Redux state, returns the subset to persist. * Default: identity (persist everything). * * deserializeOnLoad: Called when a fetch_blob response arrives. * Receives the raw blob from the server and the current Redux state. * Returns the blob to merge (via shallow spread) into current state. * Default: identity (merge entire blob). */ interface ReduxLoggerOptions { serializeForSave?: (state: JSONObject) => JSONObject; deserializeOnLoad?: (blob: JSONObject, currentState: JSONObject) => JSONObject; /** * Cross-tab state sync via redux-state-sync. Default: false (off). * * - false (default): nothing is broadcast. * - true: broadcast every action to other store instances in the same * browser — EXCEPT lo_event's own lifecycle actions (see below). * - { predicate }: broadcast only actions `predicate(action)` approves * (still minus the lifecycle actions). Lets the app drop events that must * not cross tabs — e.g. content-load events, which are per-tab. * * Regardless of true/predicate, lo_event NEVER broadcasts its own lifecycle * actions (SET_STATE — a full-state replace from blob restore — and * LOCKFIELDS), since those would clobber or duplicate state across tabs. * * Off by default because, unfiltered, lifecycle/content actions (and * non-idempotent reactive effects) echo between tabs and corrupt state. */ stateSync?: boolean | { predicate?: (action: ReduxAction) => boolean; }; } /** Subscribe to persistence status changes (save status, connected, loaded). */ declare function subscribeStatus(listener: () => void): () => void; /** Snapshot of save status for useSyncExternalStore. */ declare function getSaveStatus(): SaveStatus; /** Snapshot of connection status. null = no websocket, true/false = connected/disconnected. */ declare function getConnected(): boolean | null; /** Snapshot of loaded status (a fetch_blob load cycle has resolved). */ declare function getLoaded(): boolean; /** Snapshot of the sticky fatal condition (null = none). */ declare function getFatal(): FatalState; /** * Update the redux logger's state with `data`. * This is fired when consuming a custom `fetch_blob` event. */ declare function handleLoadState(data: unknown): void; /** * Immediately flush any pending debounced saves. * Available for programmatic use (e.g. beforeunload handlers). */ declare function saveNow(): void; declare const updateComponentStateReducer: ({}: Record) => ReducerFn; declare const registerReducer: (keys: string | string[], reducer: (state: S, action: A) => S) => (state: S, action: A) => S; declare let store: redux.Store>; declare function setState(state: JSONObject): void; declare function reduxLogger(subscribers?: Array<(event: unknown) => void>, options?: ReduxLoggerOptions): Logger; declare const awaitEvent: () => unknown | Promise; /** * Consume an `auth` DOM CustomEvent (dispatched by websocketLogger when the * server echoes `{status:'auth', ...}`) and land the resolved user identity * in Redux as `state.application_state.system.currentUser`. * * We dispatch an `EMIT_EVENT` with event type `SET_CURRENT_USER`, scope * `system`, and the full user object. Applications that register a field * for `currentUser` will pick this up via their normal field-reducer wiring. * Applications that don't register a matching reducer will simply no-op, * which is the correct default. * * No IS_LOADED gating: auth arrives on every connection, even before the * first fetch_blob round-trip, and we want currentUser available as soon as * it's known so downstream code (e.g., fetch_blob gating) can proceed. */ declare function handleAuth(user: unknown): void; export { type FatalState, type ReduxLoggerOptions, type SaveStatus, awaitEvent, getConnected, getFatal, getLoaded, getSaveStatus, handleAuth, handleLoadState, reduxLogger, registerReducer, saveNow, setState, store, subscribeStatus, updateComponentStateReducer };